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