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/sieve-script.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "compat.h"
5
#include "unichar.h"
6
#include "str.h"
7
#include "str-sanitize.h"
8
#include "hash.h"
9
#include "array.h"
10
#include "eacces-error.h"
11
#include "mkdir-parents.h"
12
#include "istream.h"
13
14
#include "sieve-common.h"
15
#include "sieve-limits.h"
16
#include "sieve-error.h"
17
#include "sieve-dump.h"
18
#include "sieve-binary.h"
19
20
#include "sieve-storage-private.h"
21
#include "sieve-script-private.h"
22
23
/*
24
 * Script name
25
 */
26
27
bool sieve_script_name_is_valid(const char *scriptname)
28
0
{
29
0
  ARRAY_TYPE(unichars) uni_name;
30
0
  unsigned int count, i;
31
0
  const unichar_t *name_chars;
32
0
  size_t namelen = strlen(scriptname);
33
34
  /* Check minimum length */
35
0
  if (namelen == 0)
36
0
    return FALSE;
37
38
  /* Check worst-case maximum length */
39
0
  if (namelen > SIEVE_MAX_SCRIPT_NAME_LEN * 4)
40
0
    return FALSE;
41
42
  /* Intialize array for unicode characters */
43
0
  t_array_init(&uni_name, namelen * 4);
44
45
  /* Convert UTF-8 to UCS4/UTF-32 */
46
0
  if (uni_utf8_to_ucs4(scriptname, &uni_name) < 0)
47
0
    return FALSE;
48
0
  name_chars = array_get(&uni_name, &count);
49
50
  /* Check true maximum length */
51
0
  if (count > SIEVE_MAX_SCRIPT_NAME_LEN)
52
0
    return FALSE;
53
54
  /* Scan name for invalid characters
55
   *   FIXME: compliance with Net-Unicode Definition (Section 2 of
56
   *          RFC 5198) is not checked fully and no normalization
57
   *          is performed.
58
   */
59
0
  for (i = 0; i < count; i++) {
60
    /* 0000-001F; [CONTROL CHARACTERS] */
61
0
    if (name_chars[i] <= 0x001f)
62
0
      return FALSE;
63
    /* 002F; SLASH (not RFC-prohibited, but '/' is dangerous) */
64
0
    if (name_chars[i] == 0x002f)
65
0
      return FALSE;
66
    /* 007F; DELETE */
67
0
    if (name_chars[i] == 0x007f)
68
0
      return FALSE;
69
    /* 0080-009F; [CONTROL CHARACTERS] */
70
0
    if (name_chars[i] >= 0x0080 && name_chars[i] <= 0x009f)
71
0
      return FALSE;
72
    /* 00FF */
73
0
    if (name_chars[i] == 0x00ff)
74
0
      return FALSE;
75
    /* 2028; LINE SEPARATOR */
76
    /* 2029; PARAGRAPH SEPARATOR */
77
0
    if (name_chars[i] == 0x2028 || name_chars[i] == 0x2029)
78
0
      return FALSE;
79
0
  }
80
81
0
  return TRUE;
82
0
}
83
84
/*
85
 * Script instance
86
 */
87
88
static void sieve_script_update_event(struct sieve_script *script)
89
0
{
90
0
  if (script->name == NULL)
91
0
    event_set_append_log_prefix(script->event, "script: ");
92
0
  else {
93
0
    event_add_str(script->event, "script_name", script->name);
94
0
    event_set_append_log_prefix(
95
0
      script->event, t_strdup_printf("script '%s': ",
96
0
                   script->name));
97
0
  }
98
0
}
99
100
void sieve_script_init(struct sieve_script *script,
101
           struct sieve_storage *storage,
102
           const struct sieve_script *script_class,
103
           const char *name)
104
0
{
105
0
  i_assert(storage != NULL);
106
107
0
  script->script_class = script_class;
108
0
  script->refcount = 1;
109
0
  script->storage = storage;
110
0
  script->name = p_strdup_empty(script->pool, name);
111
112
0
  script->event = event_create(storage->event);
113
0
  sieve_script_update_event(script);
114
115
0
  sieve_storage_ref(storage);
116
0
}
117
118
static int
119
sieve_script_create_common(struct sieve_instance *svinst,
120
         const char *cause, const char *type,
121
         const char *name, bool open,
122
         struct sieve_script **script_r,
123
         enum sieve_error *error_code_r,
124
         const char **error_r)
125
0
{
126
0
  struct sieve_storage_sequence *sseq;
127
128
0
  *script_r = NULL;
129
0
  sieve_error_args_init(&error_code_r, &error_r);
130
131
0
  if (sieve_storage_sequence_create(svinst, svinst->event, cause, type,
132
0
            &sseq, error_code_r, error_r) < 0)
133
0
    return -1;
134
135
0
  struct sieve_storage *storage;
136
0
  struct sieve_script *script;
137
0
  int ret;
138
139
  /* Find the first storage that has the script */
140
0
  for (;;) {
141
0
    *error_code_r = SIEVE_ERROR_NONE;
142
0
    *error_r = NULL;
143
0
    ret = sieve_storage_sequence_next(sseq, &storage,
144
0
              error_code_r, error_r);
145
0
    if (ret == 0)
146
0
      break;
147
0
    if (ret < 0) {
148
0
      if (*error_code_r == SIEVE_ERROR_NOT_FOUND)
149
0
        continue;
150
0
      ret = -1;
151
0
      break;
152
0
    }
153
0
    if (sieve_storage_get_script(storage, name,
154
0
               &script, error_code_r) < 0) {
155
0
      if (*error_code_r == SIEVE_ERROR_NOT_FOUND) {
156
0
        sieve_storage_unref(&storage);
157
0
        continue;
158
0
      }
159
0
      *error_r = sieve_storage_get_last_error(
160
0
        storage, error_code_r);
161
0
      ret = -1;
162
0
    } else {
163
0
      ret = 1;
164
0
    }
165
0
    sieve_storage_unref(&storage);
166
0
    if (ret > 0 && open &&
167
0
        sieve_script_open(script, error_code_r) < 0) {
168
0
      *error_r = sieve_script_get_last_error(
169
0
        script, error_code_r);
170
0
      sieve_script_unref(&script);
171
0
      if (*error_code_r == SIEVE_ERROR_NOT_FOUND)
172
0
        continue;
173
0
      ret = -1;
174
0
    }
175
0
    break;
176
0
  }
177
178
0
  if (ret > 0) {
179
0
    *script_r = script;
180
0
    ret = 0;
181
0
  } else if (ret == 0) {
182
0
    i_assert(*error_code_r == SIEVE_ERROR_NONE);
183
0
    sieve_error_create_script_not_found(
184
0
      name, error_code_r, error_r);
185
0
    ret = -1;
186
0
  }
187
188
0
  sieve_storage_sequence_free(&sseq);
189
0
  return ret;
190
0
}
191
192
int sieve_script_create(struct sieve_instance *svinst,
193
      const char *cause, const char *type, const char *name,
194
      struct sieve_script **script_r,
195
      enum sieve_error *error_code_r, const char **error_r)
196
0
{
197
0
  return sieve_script_create_common(svinst, cause, type, name, FALSE,
198
0
            script_r, error_code_r, error_r);
199
0
}
200
201
int sieve_script_create_in(struct sieve_instance *svinst, const char *cause,
202
         const char *storage_name, const char *name,
203
         struct sieve_script **script_r,
204
         enum sieve_error *error_code_r,
205
         const char **error_r)
206
0
{
207
0
  struct sieve_storage *storage;
208
0
  int ret;
209
210
0
  *script_r = NULL;
211
0
  sieve_error_args_init(&error_code_r, &error_r);
212
213
0
  if (sieve_storage_create(svinst, svinst->event, cause, storage_name, 0,
214
0
         &storage, error_code_r, error_r) < 0)
215
0
    return -1;
216
0
  ret = sieve_storage_get_script_direct(storage, name, script_r, NULL);
217
0
  if (ret < 0)
218
0
    *error_r = sieve_storage_get_last_error(storage, error_code_r);
219
0
  sieve_storage_unref(&storage);
220
0
  return ret;
221
0
}
222
223
void sieve_script_ref(struct sieve_script *script)
224
0
{
225
0
  script->refcount++;
226
0
}
227
228
void sieve_script_unref(struct sieve_script **_script)
229
0
{
230
0
  struct sieve_script *script = *_script;
231
232
0
  if (script == NULL)
233
0
    return;
234
0
  *_script = NULL;
235
236
0
  i_assert(script->refcount > 0);
237
0
  if (--script->refcount != 0)
238
0
    return;
239
240
0
  if (script->stream != NULL) {
241
0
    struct event_passthrough *e =
242
0
      event_create_passthrough(script->event)->
243
0
      set_name("sieve_script_closed");
244
0
    e_debug(e->event(), "Closed script");
245
0
  }
246
0
  i_stream_unref(&script->stream);
247
248
0
  if (script->v.destroy != NULL)
249
0
    script->v.destroy(script);
250
251
0
  sieve_storage_unref(&script->storage);
252
0
  event_unref(&script->event);
253
0
  pool_unref(&script->pool);
254
0
}
255
256
int sieve_script_open(struct sieve_script *script,
257
          enum sieve_error *error_code_r)
258
0
{
259
0
  struct sieve_storage *storage = script->storage;
260
0
  int ret;
261
262
0
  sieve_error_args_init(&error_code_r, NULL);
263
0
  sieve_storage_clear_error(storage);
264
265
0
  if (script->open)
266
0
    return 0;
267
268
0
  ret = script->v.open(script);
269
0
  i_assert(ret <= 0);
270
0
  if (ret < 0) {
271
0
    i_assert(storage->error_code != SIEVE_ERROR_NONE);
272
0
    i_assert(storage->error != NULL);
273
0
    *error_code_r = storage->error_code;
274
0
    return -1;
275
0
  }
276
277
0
  i_assert(script->name != NULL);
278
0
  script->open = TRUE;
279
280
0
  sieve_script_update_event(script);
281
0
  e_debug(script->event, "Opened from '%s'", storage->name);
282
0
  return 0;
283
0
}
284
285
int sieve_script_open_as(struct sieve_script *script, const char *name,
286
       enum sieve_error *error_code_r)
287
0
{
288
0
  if (sieve_script_open(script, error_code_r) < 0)
289
0
    return -1;
290
291
  /* override name */
292
0
  i_assert(name != NULL && *name != '\0');
293
0
  script->name = p_strdup(script->pool, name);
294
0
  sieve_script_update_event(script);
295
0
  return 0;
296
0
}
297
298
int sieve_script_create_open(struct sieve_instance *svinst,
299
           const char *cause, const char *type,
300
           const char *name, struct sieve_script **script_r,
301
           enum sieve_error *error_code_r,
302
           const char **error_r)
303
0
{
304
0
  return sieve_script_create_common(svinst, cause, type, name, TRUE,
305
0
            script_r, error_code_r, error_r);
306
0
}
307
308
int sieve_script_create_open_in(struct sieve_instance *svinst,
309
        const char *cause,
310
        const char *storage_name, const char *name,
311
        struct sieve_script **script_r,
312
        enum sieve_error *error_code_r,
313
        const char **error_r)
314
0
{
315
0
  struct sieve_script *script;
316
317
0
  *script_r = NULL;
318
0
  sieve_error_args_init(&error_code_r, &error_r);
319
320
0
  if (sieve_script_create_in(svinst, cause, storage_name, name,
321
0
           &script, error_code_r, error_r) < 0)
322
0
    return -1;
323
324
0
  if (sieve_script_open(script, NULL) < 0) {
325
0
    *error_r = sieve_script_get_last_error(script, error_code_r);
326
0
    sieve_script_unref(&script);
327
0
    return -1;
328
0
  }
329
330
0
  *script_r = script;
331
0
  return 0;
332
0
}
333
334
int sieve_script_check(struct sieve_instance *svinst,
335
           const char *cause, const char *type, const char *name,
336
           enum sieve_error *error_code_r, const char **error_r)
337
0
{
338
0
  struct sieve_script *script;
339
0
  enum sieve_error error_code;
340
341
0
  sieve_error_args_init(&error_code_r, &error_r);
342
343
0
  if (sieve_script_create_open(svinst, cause, type, name,
344
0
             &script, &error_code, error_r) < 0)
345
0
    return (*error_code_r == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
346
347
0
  sieve_script_unref(&script);
348
0
  return 1;
349
0
}
350
351
/*
352
 * Properties
353
 */
354
355
const char *sieve_script_name(const struct sieve_script *script)
356
0
{
357
0
  return script->name;
358
0
}
359
360
const char *sieve_script_label(const struct sieve_script *script)
361
0
{
362
0
  if (*script->name == '\0')
363
0
    return script->storage->name;
364
0
  return t_strconcat(script->storage->name, "/", script->name, NULL);
365
0
}
366
367
const char *sieve_script_storage_type(const struct sieve_script *script)
368
0
{
369
0
  return script->storage->type;
370
0
}
371
372
const char *sieve_script_cause(const struct sieve_script *script)
373
0
{
374
0
  return script->storage->cause;
375
0
}
376
377
struct sieve_instance *sieve_script_svinst(const struct sieve_script *script)
378
0
{
379
0
  return script->storage->svinst;
380
0
}
381
382
int sieve_script_get_size(struct sieve_script *script, uoff_t *size_r)
383
0
{
384
0
  struct istream *stream;
385
0
  int ret;
386
387
0
  if (script->v.get_size != NULL) {
388
0
    if ((ret = script->v.get_size(script, size_r)) != 0)
389
0
      return ret;
390
0
  }
391
392
  /* Try getting size from the stream */
393
0
  if (script->stream == NULL &&
394
0
      sieve_script_get_stream(script, &stream, NULL) < 0)
395
0
    return -1;
396
397
0
  if (i_stream_get_size(script->stream, TRUE, size_r) < 0) {
398
0
    sieve_storage_set_critical(script->storage,
399
0
      "i_stream_get_size(%s) failed: %s",
400
0
      i_stream_get_name(script->stream),
401
0
      i_stream_get_error(script->stream));
402
0
    return -1;
403
0
  }
404
0
  return 0;
405
0
}
406
407
bool sieve_script_is_open(const struct sieve_script *script)
408
0
{
409
0
  return script->open;
410
0
}
411
412
bool sieve_script_is_default(const struct sieve_script *script)
413
0
{
414
0
  return script->storage->is_default;
415
0
}
416
417
/*
418
 * Stream management
419
 */
420
421
int sieve_script_get_stream(struct sieve_script *script,
422
          struct istream **stream_r,
423
          enum sieve_error *error_code_r)
424
0
{
425
0
  struct sieve_storage *storage = script->storage;
426
0
  int ret;
427
428
0
  sieve_error_args_init(&error_code_r, NULL);
429
0
  sieve_storage_clear_error(storage);
430
431
0
  if (script->stream != NULL) {
432
0
    *stream_r = script->stream;
433
0
    return 0;
434
0
  }
435
436
  // FIXME: necessary?
437
0
  i_assert(script->open);
438
439
0
  T_BEGIN {
440
0
    ret = script->v.get_stream(script, &script->stream);
441
0
  } T_END;
442
443
0
  if (ret < 0) {
444
0
    i_assert(storage->error_code != SIEVE_ERROR_NONE);
445
0
    i_assert(storage->error != NULL);
446
0
    *error_code_r = storage->error_code;
447
448
0
    struct event_passthrough *e =
449
0
      event_create_passthrough(script->event)->
450
0
      add_str("error", storage->error)->
451
0
      set_name("sieve_script_opened");
452
0
    e_debug(e->event(), "Failed to open script for reading: %s",
453
0
      storage->error);
454
0
    return -1;
455
0
  }
456
457
0
  struct event_passthrough *e =
458
0
    event_create_passthrough(script->event)->
459
0
    set_name("sieve_script_opened");
460
0
  e_debug(e->event(), "Opened script for reading");
461
462
0
  *stream_r = script->stream;
463
0
  return 0;
464
0
}
465
466
/*
467
 * Comparison
468
 */
469
470
int sieve_script_cmp(const struct sieve_script *script1,
471
         const struct sieve_script *script2)
472
0
{
473
0
  int ret;
474
475
0
  if (script1 == script2)
476
0
    return 0;
477
0
  if (script1 == NULL || script2 == NULL)
478
0
    return (script1 == NULL ? -1 : 1);
479
0
  if (script1->script_class != script2->script_class)
480
0
    return (script1->script_class > script2->script_class ? 1 : -1);
481
482
0
  if (script1->v.cmp == NULL) {
483
0
    ret = sieve_storage_cmp(script1->storage, script2->storage);
484
0
    if (ret != 0)
485
0
      return (ret < 0 ? -1 : 1);
486
487
0
    return null_strcmp(script1->name, script2->name);
488
0
  }
489
490
0
  return script1->v.cmp(script1, script2);
491
0
}
492
493
unsigned int sieve_script_hash(const struct sieve_script *script)
494
0
{
495
0
  if (script == NULL)
496
0
    return 0;
497
498
0
  unsigned int hash = 0;
499
500
0
  hash ^= POINTER_CAST_TO(script->script_class, unsigned int);
501
0
  hash ^= sieve_storage_hash(script->storage);
502
0
  hash ^= str_hash(script->name);
503
504
0
  return hash;
505
0
}
506
507
/*
508
 * Binary
509
 */
510
511
int sieve_script_binary_read_metadata(struct sieve_script *script,
512
              struct sieve_binary_block *sblock,
513
              sieve_size_t *offset)
514
0
{
515
0
  struct sieve_binary *sbin = sieve_binary_block_get_binary(sblock);
516
0
  string_t *storage_class, *storage_name, *name;
517
0
  unsigned int version;
518
519
0
  if ((sieve_binary_block_get_size(sblock) - *offset) == 0)
520
0
    return 0;
521
522
  /* storage class */
523
0
  if (!sieve_binary_read_string(sblock, offset, &storage_class)) {
524
0
    e_error(script->event,
525
0
      "Binary '%s' has invalid metadata for script '%s': "
526
0
      "Invalid storage class",
527
0
      sieve_binary_path(sbin), sieve_script_label(script));
528
0
    return -1;
529
0
  }
530
0
  if (strcmp(str_c(storage_class), script->driver_name) != 0) {
531
0
    e_debug(script->event,
532
0
      "Binary '%s' reports unexpected driver name for script '%s' "
533
0
      "('%s' rather than '%s')",
534
0
      sieve_binary_path(sbin), sieve_script_label(script),
535
0
      str_c(storage_class), script->driver_name);
536
0
    return 0;
537
0
  }
538
539
  /* version */
540
0
  if (!sieve_binary_read_unsigned(sblock, offset, &version)) {
541
0
    e_error(script->event,
542
0
      "Binary '%s' has invalid metadata for script '%s': "
543
0
      "Invalid version",
544
0
      sieve_binary_path(sbin), sieve_script_label(script));
545
0
    return -1;
546
0
  }
547
0
  if (script->storage->version != version) {
548
0
    e_debug(script->event,
549
0
      "Binary '%s' was compiled with "
550
0
      "a different version of the '%s' script storage class "
551
0
      "(compiled v%d, expected v%d; "
552
0
        "automatically fixed when re-compiled)",
553
0
      sieve_binary_path(sbin), script->driver_name,
554
0
      version, script->storage->version);
555
0
    return 0;
556
0
  }
557
558
  /* storage */
559
0
  if (!sieve_binary_read_string(sblock, offset, &storage_name)) {
560
0
    e_error(script->event,
561
0
      "Binary '%s' has invalid metadata for script '%s': "
562
0
      "Invalid storage name",
563
0
      sieve_binary_path(sbin), sieve_script_label(script));
564
0
    return -1;
565
0
  }
566
0
  if (str_len(storage_name) > 0 &&
567
0
      strcmp(str_c(storage_name), script->storage->name) != 0) {
568
0
    e_debug(script->event,
569
0
      "Binary '%s' reports different storage "
570
0
      "for script '%s' (binary points to '%s')",
571
0
      sieve_binary_path(sbin), sieve_script_label(script),
572
0
      str_c(storage_name));
573
0
    return 0;
574
0
  }
575
576
  /* name */
577
0
  if (!sieve_binary_read_string(sblock, offset, &name)) {
578
0
    e_error(script->event,
579
0
      "Binary '%s' has invalid metadata for script '%s': "
580
0
      "Invalid script name",
581
0
      sieve_binary_path(sbin), sieve_script_label(script));
582
0
    return -1;
583
0
  }
584
0
  if (str_len(name) > 0 && strcmp(str_c(name), script->name) != 0) {
585
0
    e_debug(script->event,
586
0
      "Binary '%s' reports different script name "
587
0
      "for script '%s' (binary points to '%s/%s')",
588
0
      sieve_binary_path(sbin), sieve_script_label(script),
589
0
      str_c(storage_name), str_c(name));
590
0
    return 0;
591
0
  }
592
593
0
  if (script->v.binary_read_metadata == NULL)
594
0
    return 1;
595
596
0
  return script->v.binary_read_metadata(script, sblock, offset);
597
0
}
598
599
void sieve_script_binary_write_metadata(struct sieve_script *script,
600
          struct sieve_binary_block *sblock)
601
0
{
602
0
  struct sieve_binary *sbin = sieve_binary_block_get_binary(sblock);
603
0
  struct sieve_instance *svinst = sieve_binary_svinst(sbin);
604
605
0
  sieve_binary_emit_cstring(sblock, script->driver_name);
606
0
  sieve_binary_emit_unsigned(sblock, script->storage->version);
607
608
0
  if (HAS_ALL_BITS(svinst->flags, SIEVE_FLAG_COMMAND_LINE)) {
609
0
    sieve_binary_emit_cstring(sblock, "");
610
0
    sieve_binary_emit_cstring(sblock, "");
611
0
  } else {
612
0
    sieve_binary_emit_cstring(sblock, script->storage->name);
613
0
    sieve_binary_emit_cstring(sblock, script->name);
614
0
  }
615
616
0
  if (script->v.binary_write_metadata == NULL)
617
0
    return;
618
619
0
  script->v.binary_write_metadata(script, sblock);
620
0
}
621
622
bool sieve_script_binary_dump_metadata(struct sieve_script *script,
623
               struct sieve_dumptime_env *denv,
624
               struct sieve_binary_block *sblock,
625
               sieve_size_t *offset)
626
0
{
627
0
  struct sieve_binary *sbin = sieve_binary_block_get_binary(sblock);
628
0
  struct sieve_instance *svinst = sieve_binary_svinst(sbin);
629
0
  string_t *storage_class, *storage_name, *name;
630
0
  struct sieve_script *adhoc_script = NULL;
631
0
  unsigned int version;
632
0
  bool result = TRUE;
633
634
  /* storage class */
635
0
  if (!sieve_binary_read_string(sblock, offset, &storage_class))
636
0
    return FALSE;
637
0
  sieve_binary_dumpf(denv, "class = %s\n", str_c(storage_class));
638
639
  /* version */
640
0
  if (!sieve_binary_read_unsigned(sblock, offset, &version))
641
0
    return FALSE;
642
0
  sieve_binary_dumpf(denv, "class.version = %d\n", version);
643
644
  /* storage */
645
0
  if (!sieve_binary_read_string(sblock, offset, &storage_name))
646
0
    return FALSE;
647
0
  if (str_len(storage_name) == 0)
648
0
    sieve_binary_dumpf(denv, "storage = (unavailable)\n");
649
0
  else
650
0
    sieve_binary_dumpf(denv, "storage = %s\n", str_c(storage_name));
651
652
  /* name */
653
0
  if (!sieve_binary_read_string(sblock, offset, &name))
654
0
    return FALSE;
655
0
  if (str_len(name) == 0)
656
0
    sieve_binary_dumpf(denv, "name = (unavailable)\n");
657
0
  else
658
0
    sieve_binary_dumpf(denv, "name = %s\n", str_c(name));
659
660
0
  if (script == NULL) {
661
0
    adhoc_script = NULL;
662
0
    if (sieve_script_create_in(svinst, SIEVE_SCRIPT_CAUSE_ANY,
663
0
             str_c(storage_name), str_c(name),
664
0
             &script, NULL, NULL) == 0)
665
0
      adhoc_script = script;
666
0
  }
667
668
0
  if (script != NULL && script->v.binary_dump_metadata != NULL) {
669
0
    result = script->v.binary_dump_metadata(
670
0
      script, denv, sblock, offset);
671
0
  }
672
673
0
  sieve_script_unref(&adhoc_script);
674
0
  return result;
675
0
}
676
677
int sieve_script_binary_load_default(struct sieve_script *script,
678
             const char *path,
679
             struct sieve_binary **sbin_r)
680
0
{
681
0
  struct sieve_instance *svinst = script->storage->svinst;
682
0
  enum sieve_error error_code;
683
684
0
  if (path == NULL) {
685
0
    sieve_script_set_error(
686
0
      script, SIEVE_ERROR_NOT_POSSIBLE,
687
0
      "Cannot load script binary for this storage");
688
0
    return -1;
689
0
  }
690
691
0
  if (sieve_binary_open(svinst, path, script, sbin_r, &error_code) < 0) {
692
0
    sieve_script_set_error(script, error_code,
693
0
               "Failed to load script binary");
694
0
    return -1;
695
0
  }
696
0
  return 0;
697
0
}
698
699
int sieve_script_binary_load(struct sieve_script *script,
700
           struct sieve_binary **sbin_r,
701
           enum sieve_error *error_code_r)
702
0
{
703
0
  struct sieve_storage *storage = script->storage;
704
0
  int ret;
705
706
0
  *sbin_r = NULL;
707
0
  sieve_error_args_init(&error_code_r, NULL);
708
0
  sieve_storage_clear_error(storage);
709
710
0
  if (script->v.binary_load == NULL) {
711
0
    sieve_script_set_error(
712
0
      script, SIEVE_ERROR_NOT_POSSIBLE,
713
0
      "Cannot load script binary for this storage type");
714
0
    ret = -1;
715
0
  } else {
716
0
    ret = script->v.binary_load(script, sbin_r);
717
0
    i_assert(ret <= 0);
718
0
    i_assert(ret < 0 || *sbin_r != NULL);
719
0
  }
720
721
0
  if (ret < 0) {
722
0
    i_assert(storage->error_code != SIEVE_ERROR_NONE);
723
0
    i_assert(storage->error != NULL);
724
0
    *error_code_r = script->storage->error_code;
725
0
    return -1;
726
0
  }
727
0
  return 0;
728
0
}
729
730
int sieve_script_binary_save_default(struct sieve_script *script ATTR_UNUSED,
731
             struct sieve_binary *sbin,
732
             const char *path, bool update,
733
             mode_t save_mode)
734
0
{
735
0
  struct sieve_storage *storage = script->storage;
736
0
  enum sieve_error error_code;
737
0
  int ret;
738
739
0
  if (path == NULL) {
740
0
    e_debug(script->event, "No path to save Sieve script");
741
0
    sieve_script_set_error(
742
0
      script, SIEVE_ERROR_NOT_POSSIBLE,
743
0
      "Cannot save script binary for this storage");
744
0
    return -1;
745
0
  }
746
747
0
  if (storage->bin_path != NULL &&
748
0
      str_begins_with(path, storage->bin_path) &&
749
0
      sieve_storage_setup_bin_path(
750
0
    script->storage, mkdir_get_executable_mode(save_mode)) < 0)
751
0
    return -1;
752
753
0
  e_debug(script->event, "Saving binary to '%s'", path);
754
755
0
  ret = sieve_binary_save(sbin, path, update, save_mode, &error_code);
756
0
  if (ret < 0) {
757
0
    sieve_script_set_error(script, error_code,
758
0
               "Failed to save script binary");
759
0
    return -1;
760
0
  }
761
0
  return 0;
762
0
}
763
764
int sieve_script_binary_save(struct sieve_script *script,
765
           struct sieve_binary *sbin, bool update,
766
           enum sieve_error *error_code_r)
767
0
{
768
0
  struct sieve_storage *storage = script->storage;
769
0
  struct sieve_script *bin_script = sieve_binary_script(sbin);
770
0
  int ret;
771
772
0
  sieve_error_args_init(&error_code_r, NULL);
773
0
  sieve_storage_clear_error(storage);
774
775
0
  i_assert(bin_script == NULL || sieve_script_equals(bin_script, script));
776
777
0
  if (script->v.binary_save == NULL) {
778
0
    sieve_script_set_error(
779
0
      script, SIEVE_ERROR_NOT_POSSIBLE,
780
0
      "Cannot save script binary for this storage type");
781
0
    ret = -1;
782
0
  } else {
783
0
    ret = script->v.binary_save(script, sbin, update);
784
0
  }
785
786
0
  if (ret < 0) {
787
0
    i_assert(storage->error_code != SIEVE_ERROR_NONE);
788
0
    i_assert(storage->error != NULL);
789
0
    *error_code_r = script->storage->error_code;
790
0
    return -1;
791
0
  }
792
0
  return 0;
793
0
}
794
795
const char *sieve_script_binary_get_prefix(struct sieve_script *script)
796
0
{
797
0
  struct sieve_storage *storage = script->storage;
798
799
0
  if (storage->bin_path != NULL &&
800
0
      sieve_storage_setup_bin_path(storage, 0700) >= 0)
801
0
    return t_strconcat(storage->bin_path, "/", script->name, NULL);
802
0
  if (script->v.binary_get_prefix == NULL)
803
0
    return NULL;
804
805
0
  return script->v.binary_get_prefix(script);
806
0
}
807
808
/*
809
 * Management
810
 */
811
812
static int
813
sieve_script_copy_from_default(struct sieve_script *script, const char *newname)
814
0
{
815
0
  struct sieve_storage *storage = script->storage;
816
0
  struct istream *input;
817
0
  int ret;
818
819
  /* copy from default */
820
0
  if ((ret = sieve_script_open(script, NULL)) < 0 ||
821
0
      (ret = sieve_script_get_stream(script, &input, NULL)) < 0) {
822
0
    sieve_storage_copy_error(storage->default_storage_for, storage);
823
0
    return ret;
824
0
  }
825
826
0
  ret = sieve_storage_save_as(storage->default_storage_for,
827
0
            input, newname);
828
0
  if (ret < 0) {
829
0
    sieve_storage_copy_error(storage, storage->default_storage_for);
830
0
  } else if (sieve_script_is_active(script) > 0) {
831
0
    struct sieve_script *newscript;
832
0
    enum sieve_error error_code;
833
834
0
    if (sieve_storage_open_script(storage->default_storage_for,
835
0
                newname, &newscript,
836
0
                &error_code) < 0) {
837
      /* Somehow not actually saved */
838
0
      ret = (error_code == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
839
0
    } else if (sieve_script_activate(newscript, (time_t)-1) < 0) {
840
      /* Failed to activate; roll back */
841
0
      ret = -1;
842
0
      (void)sieve_script_delete(newscript, TRUE);
843
0
    }
844
0
    sieve_script_unref(&newscript);
845
846
0
    if (ret < 0) {
847
0
      e_error(storage->event,
848
0
        "Failed to implicitly activate script '%s' "
849
0
        "after rename", newname);
850
0
      sieve_storage_copy_error(storage->default_storage_for,
851
0
             storage);
852
0
    }
853
0
  }
854
855
0
  return ret;
856
0
}
857
858
int sieve_script_rename(struct sieve_script *script, const char *newname)
859
0
{
860
0
  struct sieve_storage *storage = script->storage;
861
0
  const char *oldname = script->name;
862
0
  struct event_passthrough *event;
863
0
  int ret;
864
865
0
  i_assert(newname != NULL);
866
0
  sieve_storage_clear_error(storage);
867
868
  /* Check script name */
869
0
  if (!sieve_script_name_is_valid(newname)) {
870
0
    sieve_script_set_error(script,
871
0
      SIEVE_ERROR_BAD_PARAMS,
872
0
      "Invalid new Sieve script name '%s'.",
873
0
      str_sanitize(newname, 80));
874
0
    return -1;
875
0
  }
876
877
0
  i_assert(script->open); // FIXME: auto-open?
878
879
0
  if (storage->default_storage_for == NULL) {
880
0
    i_assert((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
881
882
    /* rename script */
883
0
    i_assert(script->v.rename != NULL);
884
0
    ret = script->v.rename(script, newname);
885
886
    /* rename INBOX mailbox attribute */
887
0
    if (ret >= 0 && oldname != NULL) {
888
0
      (void)sieve_storage_sync_script_rename(storage, oldname,
889
0
                     newname);
890
0
    }
891
0
  } else if (sieve_storage_check_script(storage->default_storage_for,
892
0
                newname, NULL) > 0) {
893
0
    sieve_script_set_error(script, SIEVE_ERROR_EXISTS,
894
0
      "A sieve script with that name already exists.");
895
0
    sieve_storage_copy_error(storage->default_storage_for, storage);
896
0
    ret = -1;
897
0
  } else {
898
0
    ret = sieve_script_copy_from_default(script, newname);
899
0
  }
900
901
0
  event = event_create_passthrough(script->event)->
902
0
    clear_field("script_name")->
903
0
    add_str("old_script_name", script->name)->
904
0
    add_str("new_script_name", newname)->
905
0
    set_name("sieve_script_renamed");
906
907
0
  if (ret >= 0) {
908
0
    e_debug(event->event(), "Script renamed to '%s'", newname);
909
0
    sieve_script_update_event(script);
910
0
  } else {
911
0
    i_assert(storage->error_code != SIEVE_ERROR_NONE);
912
0
    i_assert(storage->error != NULL);
913
0
    event = event->add_str("error", storage->error);
914
915
0
    e_debug(event->event(), "Failed to rename script: %s",
916
0
      storage->error);
917
0
  }
918
919
0
  return ret;
920
0
}
921
922
int sieve_script_delete(struct sieve_script *script, bool ignore_active)
923
0
{
924
0
  struct sieve_storage *storage = script->storage;
925
0
  bool is_active = FALSE;
926
0
  int ret = 0;
927
928
0
  i_assert(script->open); // FIXME: auto-open?
929
0
  sieve_storage_clear_error(storage);
930
931
  /* Is the requested script active? */
932
0
  if (sieve_script_is_active(script) > 0) {
933
0
    is_active = TRUE;
934
0
    if (!ignore_active) {
935
0
      sieve_script_set_error(script, SIEVE_ERROR_ACTIVE,
936
0
        "Cannot delete the active Sieve script.");
937
0
      if (storage->default_storage_for != NULL) {
938
0
        sieve_storage_copy_error(
939
0
          storage->default_storage_for, storage);
940
0
      }
941
0
      return -1;
942
0
    }
943
0
  }
944
945
  /* Trying to delete the default script? */
946
0
  if (storage->is_default) {
947
    /* ignore */
948
0
    return 0;
949
0
  }
950
951
0
  i_assert((script->storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
952
953
  /* Deactivate it explicity */
954
0
  if (ignore_active && is_active)
955
0
    (void)sieve_storage_deactivate(storage, (time_t)-1);
956
957
0
  i_assert(script->v.delete != NULL);
958
0
  ret = script->v.delete(script);
959
960
0
  if (ret >= 0) {
961
0
    struct event_passthrough *e =
962
0
      event_create_passthrough(script->event)->
963
0
      set_name("sieve_script_deleted");
964
0
    e_debug(e->event(), "Script deleted");
965
966
    /* unset INBOX mailbox attribute */
967
0
    (void)sieve_storage_sync_script_delete(storage, script->name);
968
0
  } else {
969
0
    i_assert(storage->error_code != SIEVE_ERROR_NONE);
970
0
    i_assert(storage->error != NULL);
971
972
0
    struct event_passthrough *e =
973
0
      event_create_passthrough(script->event)->
974
0
      add_str("error", storage->error)->
975
0
      set_name("sieve_script_deleted");
976
0
    e_debug(e->event(), "Failed to delete script: %s",
977
0
      storage->error);
978
0
  }
979
0
  return ret;
980
0
}
981
982
int sieve_script_is_active(struct sieve_script *script)
983
0
{
984
0
  struct sieve_storage *storage = script->storage;
985
0
  int ret;
986
987
0
  sieve_storage_clear_error(storage);
988
989
  /* Special handling if this is a default script */
990
0
  if (storage->default_storage_for != NULL) {
991
0
    ret = sieve_storage_active_script_is_default(
992
0
      storage->default_storage_for);
993
0
    if (ret < 0) {
994
0
      sieve_storage_copy_error(storage,
995
0
             storage->default_storage_for);
996
0
      i_assert(storage->error_code != SIEVE_ERROR_NONE);
997
0
      i_assert(storage->error != NULL);
998
0
    }
999
0
    return ret;
1000
0
  }
1001
1002
0
  if (script->v.is_active == NULL)
1003
0
    return 0;
1004
0
  ret = script->v.is_active(script);
1005
0
  i_assert(ret >= 0 ||
1006
0
     (storage->error_code != SIEVE_ERROR_NONE &&
1007
0
      storage->error != NULL));
1008
0
  return ret;
1009
0
}
1010
1011
int sieve_script_activate(struct sieve_script *script, time_t mtime)
1012
0
{
1013
0
  struct sieve_storage *storage = script->storage;
1014
0
  int ret = 0;
1015
1016
0
  i_assert(script->open); // FIXME: auto-open?
1017
0
  sieve_storage_clear_error(storage);
1018
1019
0
  if (storage->default_storage_for == NULL) {
1020
0
    i_assert((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
1021
1022
0
    i_assert(script->v.activate != NULL);
1023
0
    ret = script->v.activate(script);
1024
1025
0
    if (ret >= 0) {
1026
0
      struct event_passthrough *e =
1027
0
        event_create_passthrough(script->event)->
1028
0
        set_name("sieve_script_activated");
1029
0
      e_debug(e->event(), "Script activated");
1030
1031
0
      sieve_storage_set_modified(storage, mtime);
1032
0
      (void)sieve_storage_sync_script_activate(storage);
1033
0
    } else {
1034
0
      i_assert(storage->error_code != SIEVE_ERROR_NONE);
1035
0
      i_assert(storage->error != NULL);
1036
1037
0
      struct event_passthrough *e =
1038
0
        event_create_passthrough(script->event)->
1039
0
        add_str("error", storage->error)->
1040
0
        set_name("sieve_script_activated");
1041
0
      e_debug(e->event(), "Failed to activate script: %s",
1042
0
        storage->error);
1043
0
    }
1044
1045
0
  } else {
1046
    /* Activating the default script is equal to deactivating
1047
       the storage */
1048
0
    ret = sieve_storage_deactivate(storage->default_storage_for,
1049
0
                 (time_t)-1);
1050
0
    if (ret < 0) {
1051
0
      sieve_storage_copy_error(storage,
1052
0
             storage->default_storage_for);
1053
0
    }
1054
0
  }
1055
1056
0
  return ret;
1057
0
}
1058
1059
/*
1060
 * Error handling
1061
 */
1062
1063
void sieve_script_set_error(struct sieve_script *script,
1064
          enum sieve_error error_code, const char *fmt, ...)
1065
0
{
1066
0
  struct sieve_storage *storage = script->storage;
1067
0
  va_list va;
1068
1069
0
  sieve_storage_clear_error(storage);
1070
1071
0
  if (fmt != NULL) {
1072
0
    va_start(va, fmt);
1073
0
    storage->error = i_strdup_vprintf(fmt, va);
1074
0
    va_end(va);
1075
0
  }
1076
0
  storage->error_code = error_code;
1077
0
}
1078
1079
void sieve_script_set_internal_error(struct sieve_script *script)
1080
0
{
1081
0
  sieve_storage_set_internal_error(script->storage);
1082
0
}
1083
1084
void sieve_script_set_critical(struct sieve_script *script,
1085
             const char *fmt, ...)
1086
0
{
1087
0
  struct sieve_storage *storage = script->storage;
1088
1089
0
  va_list va;
1090
1091
0
  if (fmt != NULL) {
1092
0
    if ((storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0) {
1093
0
      va_start(va, fmt);
1094
0
      e_error(script->event, "%s", t_strdup_vprintf(fmt, va));
1095
0
      va_end(va);
1096
1097
0
      sieve_storage_set_internal_error(storage);
1098
1099
0
    } else {
1100
0
      sieve_storage_clear_error(storage);
1101
1102
      /* no user is involved while synchronizing, so do it the
1103
         normal way */
1104
0
      va_start(va, fmt);
1105
0
      storage->error = i_strdup_vprintf(fmt, va);
1106
0
      va_end(va);
1107
1108
0
      storage->error_code = SIEVE_ERROR_TEMP_FAILURE;
1109
0
    }
1110
0
  }
1111
0
}
1112
1113
void sieve_script_set_not_found_error(struct sieve_script *script,
1114
              const char *name)
1115
0
{
1116
0
  name = (name == NULL || *name == '\0' ? script->name : name);
1117
0
  sieve_storage_set_not_found_error(script->storage, name);
1118
0
}
1119
1120
const char *
1121
sieve_script_get_last_error(struct sieve_script *script,
1122
          enum sieve_error *error_code_r)
1123
0
{
1124
0
  return sieve_storage_get_last_error(script->storage, error_code_r);
1125
0
}
1126
1127
const char *sieve_script_get_last_error_lcase(struct sieve_script *script)
1128
0
{
1129
0
  return sieve_error_from_external(script->storage->error);
1130
0
}
1131
1132
/*
1133
 * Script sequence
1134
 */
1135
1136
int sieve_script_sequence_create(struct sieve_instance *svinst,
1137
         struct event *event_parent,
1138
         const char *cause, const char *type,
1139
         struct sieve_script_sequence **sseq_r,
1140
         enum sieve_error *error_code_r,
1141
         const char **error_r)
1142
0
{
1143
0
  struct sieve_storage_sequence *storage_seq;
1144
0
  struct sieve_script_sequence *sseq;
1145
1146
0
  *sseq_r = NULL;
1147
0
  sieve_error_args_init(&error_code_r, &error_r);
1148
1149
0
  if (sieve_storage_sequence_create(svinst, event_parent,
1150
0
            cause, type, &storage_seq,
1151
0
            error_code_r, error_r) < 0)
1152
0
    return -1;
1153
1154
0
  sseq = i_new(struct sieve_script_sequence, 1);
1155
0
  sseq->storage_seq = storage_seq;
1156
1157
0
  *sseq_r = sseq;
1158
0
  return 0;
1159
0
}
1160
1161
static int
1162
sieve_script_sequence_init_storage(struct sieve_script_sequence *sseq,
1163
           enum sieve_error *error_code_r,
1164
           const char **error_r)
1165
0
{
1166
0
  int ret;
1167
1168
0
  while (sseq->storage == NULL) {
1169
0
    ret = sieve_storage_sequence_next(sseq->storage_seq,
1170
0
              &sseq->storage,
1171
0
              error_code_r, error_r);
1172
0
    if (ret == 0)
1173
0
      return 0;
1174
0
    if (ret < 0) {
1175
0
      if (*error_code_r == SIEVE_ERROR_NOT_FOUND)
1176
0
        continue;
1177
0
      return -1;
1178
0
    }
1179
1180
0
    struct sieve_storage *storage = sseq->storage;
1181
1182
0
    i_assert(storage->v.script_sequence_init != NULL);
1183
0
    sieve_storage_clear_error(storage);
1184
0
    ret = storage->v.script_sequence_init(sseq);
1185
0
    if (ret < 0) {
1186
0
      i_assert(storage->error_code != SIEVE_ERROR_NONE);
1187
0
      i_assert(storage->error != NULL);
1188
0
      *error_code_r = storage->error_code;
1189
0
      *error_r = storage->error;
1190
0
      sieve_storage_unref(&sseq->storage);
1191
0
      if (*error_code_r != SIEVE_ERROR_NOT_FOUND)
1192
0
        return -1;
1193
0
    }
1194
0
  }
1195
0
  return 1;
1196
0
}
1197
1198
static void
1199
sieve_script_sequence_deinit_storage(struct sieve_script_sequence *sseq)
1200
0
{
1201
0
  struct sieve_storage *storage = sseq->storage;
1202
1203
0
  if (storage != NULL && storage->v.script_sequence_destroy != NULL)
1204
0
    storage->v.script_sequence_destroy(sseq);
1205
0
  sseq->storage_data = NULL;
1206
1207
0
  sieve_storage_unref(&sseq->storage);
1208
0
}
1209
1210
int sieve_script_sequence_next(struct sieve_script_sequence *sseq,
1211
             struct sieve_script **script_r,
1212
             enum sieve_error *error_code_r,
1213
             const char **error_r)
1214
0
{
1215
0
  int ret;
1216
1217
0
  *script_r = NULL;
1218
0
  sieve_error_args_init(&error_code_r, &error_r);
1219
1220
0
  while ((ret = sieve_script_sequence_init_storage(
1221
0
      sseq, error_code_r, error_r)) > 0) {
1222
0
    struct sieve_storage *storage = sseq->storage;
1223
1224
0
    i_assert(storage->v.script_sequence_next != NULL);
1225
0
    sieve_storage_clear_error(storage);
1226
0
    ret = storage->v.script_sequence_next(sseq, script_r);
1227
0
    if (ret > 0)
1228
0
      break;
1229
1230
0
    if (ret < 0) {
1231
0
      i_assert(storage->error_code != SIEVE_ERROR_NONE);
1232
0
      i_assert(storage->error != NULL);
1233
1234
0
      if (storage->error_code == SIEVE_ERROR_NOT_FOUND)
1235
0
        ret = 0;
1236
0
      else {
1237
0
        *error_code_r = storage->error_code;
1238
0
        *error_r = t_strdup(storage->error);
1239
0
      }
1240
0
    }
1241
1242
0
    sieve_script_sequence_deinit_storage(sseq);
1243
0
    if (ret < 0)
1244
0
      break;
1245
0
  }
1246
1247
0
  return ret;
1248
0
}
1249
1250
void sieve_script_sequence_free(struct sieve_script_sequence **_sseq)
1251
0
{
1252
0
  struct sieve_script_sequence *sseq = *_sseq;
1253
1254
0
  if (sseq == NULL)
1255
0
    return;
1256
0
  *_sseq = NULL;
1257
1258
0
  sieve_script_sequence_deinit_storage(sseq);
1259
0
  sieve_storage_sequence_free(&sseq->storage_seq);
1260
  i_free(sseq);
1261
0
}