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 "istream.h"
13
14 #include "sieve-common.h"
15 #include "sieve-limits.h"
16 #include "sieve-settings.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
sieve_script_name_is_valid(const char * scriptname)28 bool sieve_script_name_is_valid(const char *scriptname)
29 {
30 ARRAY_TYPE(unichars) uni_name;
31 unsigned int count, i;
32 const unichar_t *name_chars;
33 size_t namelen = strlen(scriptname);
34
35 /* Check minimum length */
36 if (namelen == 0)
37 return FALSE;
38
39 /* Check worst-case maximum length */
40 if (namelen > SIEVE_MAX_SCRIPT_NAME_LEN * 4)
41 return FALSE;
42
43 /* Intialize array for unicode characters */
44 t_array_init(&uni_name, namelen * 4);
45
46 /* Convert UTF-8 to UCS4/UTF-32 */
47 if (uni_utf8_to_ucs4(scriptname, &uni_name) < 0)
48 return FALSE;
49 name_chars = array_get(&uni_name, &count);
50
51 /* Check true maximum length */
52 if (count > SIEVE_MAX_SCRIPT_NAME_LEN)
53 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 for (i = 0; i < count; i++) {
61 /* 0000-001F; [CONTROL CHARACTERS] */
62 if (name_chars[i] <= 0x001f)
63 return FALSE;
64 /* 002F; SLASH (not RFC-prohibited, but '/' is dangerous) */
65 if (name_chars[i] == 0x002f)
66 return FALSE;
67 /* 007F; DELETE */
68 if (name_chars[i] == 0x007f)
69 return FALSE;
70 /* 0080-009F; [CONTROL CHARACTERS] */
71 if (name_chars[i] >= 0x0080 && name_chars[i] <= 0x009f)
72 return FALSE;
73 /* 00FF */
74 if (name_chars[i] == 0x00ff)
75 return FALSE;
76 /* 2028; LINE SEPARATOR */
77 /* 2029; PARAGRAPH SEPARATOR */
78 if (name_chars[i] == 0x2028 || name_chars[i] == 0x2029)
79 return FALSE;
80 }
81
82 return TRUE;
83 }
84
85 /*
86 * Script instance
87 */
88
sieve_script_init(struct sieve_script * script,struct sieve_storage * storage,const struct sieve_script * script_class,const char * location,const char * name)89 void sieve_script_init(struct sieve_script *script,
90 struct sieve_storage *storage,
91 const struct sieve_script *script_class,
92 const char *location, const char *name)
93 {
94 i_assert(storage != NULL);
95
96 script->script_class = script_class;
97 script->refcount = 1;
98 script->storage = storage;
99 script->location = p_strdup_empty(script->pool, location);
100 script->name = p_strdup(script->pool, name);
101
102 script->event = event_create(storage->event);
103 event_add_str(script->event, "script_name", name);
104 event_add_str(script->event, "script_location", location);
105 if (name == NULL)
106 event_set_append_log_prefix(script->event, "script: ");
107 else {
108 event_set_append_log_prefix(
109 script->event, t_strdup_printf("script `%s': ", name));
110 }
111
112 sieve_storage_ref(storage);
113 }
114
115 struct sieve_script *
sieve_script_create(struct sieve_instance * svinst,const char * location,const char * name,enum sieve_error * error_r)116 sieve_script_create(struct sieve_instance *svinst, const char *location,
117 const char *name, enum sieve_error *error_r)
118 {
119 struct sieve_storage *storage;
120 struct sieve_script *script;
121 enum sieve_error error;
122
123 if (error_r != NULL)
124 *error_r = SIEVE_ERROR_NONE;
125 else
126 error_r = &error;
127
128 storage = sieve_storage_create(svinst, location, 0, error_r);
129 if (storage == NULL)
130 return NULL;
131
132 script = sieve_storage_get_script(storage, name, error_r);
133
134 sieve_storage_unref(&storage);
135 return script;
136 }
137
sieve_script_ref(struct sieve_script * script)138 void sieve_script_ref(struct sieve_script *script)
139 {
140 script->refcount++;
141 }
142
sieve_script_unref(struct sieve_script ** _script)143 void sieve_script_unref(struct sieve_script **_script)
144 {
145 struct sieve_script *script = *_script;
146
147 *_script = NULL;
148
149 if (script == NULL)
150 return;
151
152 i_assert(script->refcount > 0);
153 if (--script->refcount != 0)
154 return;
155
156 if (script->stream != NULL) {
157 struct event_passthrough *e =
158 event_create_passthrough(script->event)->
159 set_name("sieve_script_closed");
160 e_debug(e->event(), "Closed script");
161 }
162 i_stream_unref(&script->stream);
163
164 if (script->v.destroy != NULL)
165 script->v.destroy(script);
166
167 sieve_storage_unref(&script->storage);
168 event_unref(&script->event);
169 pool_unref(&script->pool);
170 }
171
sieve_script_open(struct sieve_script * script,enum sieve_error * error_r)172 int sieve_script_open(struct sieve_script *script, enum sieve_error *error_r)
173 {
174 enum sieve_error error;
175
176 if (error_r != NULL)
177 *error_r = SIEVE_ERROR_NONE;
178 else
179 error_r = &error;
180
181 if (script->open)
182 return 0;
183
184 if (script->v.open(script, error_r) < 0)
185 return -1;
186
187 i_assert(script->location != NULL);
188 i_assert(script->name != NULL);
189 script->open = TRUE;
190
191 if (*script->name != '\0') {
192 e_debug(script->event, "Opened script `%s' from `%s'",
193 script->name, script->location);
194 } else {
195 e_debug(script->event, "Opened nameless script from `%s'",
196 script->location);
197 }
198 return 0;
199 }
200
sieve_script_open_as(struct sieve_script * script,const char * name,enum sieve_error * error_r)201 int sieve_script_open_as(struct sieve_script *script, const char *name,
202 enum sieve_error *error_r)
203 {
204 if (sieve_script_open(script, error_r) < 0)
205 return -1;
206
207 /* override name */
208 script->name = p_strdup(script->pool, name);
209 event_add_str(script->event, "script_name", name);
210 return 0;
211 }
212
213 struct sieve_script *
sieve_script_create_open(struct sieve_instance * svinst,const char * location,const char * name,enum sieve_error * error_r)214 sieve_script_create_open(struct sieve_instance *svinst, const char *location,
215 const char *name, enum sieve_error *error_r)
216 {
217 struct sieve_script *script;
218
219 script = sieve_script_create(svinst, location, name, error_r);
220 if (script == NULL)
221 return NULL;
222
223 if (sieve_script_open(script, error_r) < 0) {
224 sieve_script_unref(&script);
225 return NULL;
226 }
227
228 return script;
229 }
230
sieve_script_check(struct sieve_instance * svinst,const char * location,const char * name,enum sieve_error * error_r)231 int sieve_script_check(struct sieve_instance *svinst, const char *location,
232 const char *name, enum sieve_error *error_r)
233 {
234 struct sieve_script *script;
235 enum sieve_error error;
236
237 if (error_r == NULL)
238 error_r = &error;
239
240 script = sieve_script_create_open(svinst, location, name, error_r);
241 if (script == NULL)
242 return (*error_r == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
243
244 sieve_script_unref(&script);
245 return 1;
246 }
247
248 /*
249 * Properties
250 */
251
sieve_script_name(const struct sieve_script * script)252 const char *sieve_script_name(const struct sieve_script *script)
253 {
254 return script->name;
255 }
256
sieve_script_location(const struct sieve_script * script)257 const char *sieve_script_location(const struct sieve_script *script)
258 {
259 return script->location;
260 }
261
sieve_script_svinst(const struct sieve_script * script)262 struct sieve_instance *sieve_script_svinst(const struct sieve_script *script)
263 {
264 return script->storage->svinst;
265 }
266
sieve_script_get_size(struct sieve_script * script,uoff_t * size_r)267 int sieve_script_get_size(struct sieve_script *script, uoff_t *size_r)
268 {
269 struct istream *stream;
270 int ret;
271
272 if (script->v.get_size != NULL) {
273 if ((ret = script->v.get_size(script, size_r)) != 0)
274 return ret;
275 }
276
277 /* Try getting size from the stream */
278 if (script->stream == NULL &&
279 sieve_script_get_stream(script, &stream, NULL) < 0)
280 return -1;
281
282 if (i_stream_get_size(script->stream, TRUE, size_r) < 0) {
283 sieve_storage_set_critical(script->storage,
284 "i_stream_get_size(%s) failed: %s",
285 i_stream_get_name(script->stream),
286 i_stream_get_error(script->stream));
287 return -1;
288 }
289 return 0;
290 }
291
sieve_script_is_open(const struct sieve_script * script)292 bool sieve_script_is_open(const struct sieve_script *script)
293 {
294 return script->open;
295 }
296
sieve_script_is_default(const struct sieve_script * script)297 bool sieve_script_is_default(const struct sieve_script *script)
298 {
299 return script->storage->is_default;
300 }
301
302 /*
303 * Stream management
304 */
305
sieve_script_get_stream(struct sieve_script * script,struct istream ** stream_r,enum sieve_error * error_r)306 int sieve_script_get_stream(struct sieve_script *script,
307 struct istream **stream_r,
308 enum sieve_error *error_r)
309 {
310 struct sieve_storage *storage = script->storage;
311 enum sieve_error error;
312 int ret;
313
314 if (error_r != NULL)
315 *error_r = SIEVE_ERROR_NONE;
316 else
317 error_r = &error;
318
319 if (script->stream != NULL) {
320 *stream_r = script->stream;
321 return 0;
322 }
323
324 // FIXME: necessary?
325 i_assert(script->open);
326
327 T_BEGIN {
328 ret = script->v.get_stream(script, &script->stream, error_r);
329 } T_END;
330
331 if (ret < 0) {
332 struct event_passthrough *e =
333 event_create_passthrough(script->event)->
334 add_str("error", storage->error)->
335 set_name("sieve_script_opened");
336 e_debug(e->event(), "Failed to open script for reading: %s",
337 storage->error);
338 return -1;
339 }
340
341 struct event_passthrough *e =
342 event_create_passthrough(script->event)->
343 set_name("sieve_script_opened");
344 e_debug(e->event(), "Opened script for reading");
345
346 *stream_r = script->stream;
347 return 0;
348 }
349
350 /*
351 * Comparison
352 */
353
sieve_script_equals(const struct sieve_script * script,const struct sieve_script * other)354 bool sieve_script_equals(const struct sieve_script *script,
355 const struct sieve_script *other)
356 {
357 if (script == other)
358 return TRUE;
359 if (script == NULL || other == NULL)
360 return FALSE;
361 if (script->script_class != other->script_class)
362 return FALSE;
363
364 if (script->v.equals == NULL) {
365 i_assert (script->location != NULL && other->location != NULL);
366
367 return (strcmp(script->location, other->location) == 0);
368 }
369
370 return script->v.equals(script, other);
371 }
372
sieve_script_hash(const struct sieve_script * script)373 unsigned int sieve_script_hash(const struct sieve_script *script)
374 {
375 i_assert(script->name != NULL);
376
377 return str_hash(script->name);
378 }
379
380 /*
381 * Binary
382 */
383
sieve_script_binary_read_metadata(struct sieve_script * script,struct sieve_binary_block * sblock,sieve_size_t * offset)384 int sieve_script_binary_read_metadata(struct sieve_script *script,
385 struct sieve_binary_block *sblock,
386 sieve_size_t *offset)
387 {
388 struct sieve_binary *sbin = sieve_binary_block_get_binary(sblock);
389 string_t *storage_class, *location;
390 unsigned int version;
391
392 if ((sieve_binary_block_get_size(sblock) - *offset) == 0)
393 return 0;
394
395 /* storage class */
396 if (!sieve_binary_read_string(sblock, offset, &storage_class)) {
397 e_error(script->event,
398 "Binary `%s' has invalid metadata for script `%s': "
399 "Invalid storage class",
400 sieve_binary_path(sbin), script->location);
401 return -1;
402 }
403 if (strcmp(str_c(storage_class), script->driver_name) != 0) {
404 e_debug(script->event,
405 "Binary `%s' reports unexpected driver name for script `%s' "
406 "(`%s' rather than `%s')",
407 sieve_binary_path(sbin), script->location,
408 str_c(storage_class), script->driver_name);
409 return 0;
410 }
411
412 /* version */
413 if (!sieve_binary_read_unsigned(sblock, offset, &version)) {
414 e_error(script->event,
415 "Binary `%s' has invalid metadata for script `%s': "
416 "Invalid version",
417 sieve_binary_path(sbin), script->location);
418 return -1;
419 }
420 if (script->storage->version != version) {
421 e_debug(script->event,
422 "Binary `%s' was compiled with "
423 "a different version of the `%s' script storage class "
424 "(compiled v%d, expected v%d; "
425 "automatically fixed when re-compiled)",
426 sieve_binary_path(sbin), script->driver_name,
427 version, script->storage->version);
428 return 0;
429 }
430
431 /* location */
432 if (!sieve_binary_read_string(sblock, offset, &location)) {
433 e_error(script->event,
434 "Binary `%s' has invalid metadata for script `%s': "
435 "Invalid location",
436 sieve_binary_path(sbin), script->location);
437 return -1;
438 }
439 i_assert(script->location != NULL);
440 if (strcmp(str_c(location), script->location) != 0) {
441 e_debug(script->event,
442 "Binary `%s' reports different location "
443 "for script `%s' (binary points to `%s')",
444 sieve_binary_path(sbin), script->location,
445 str_c(location));
446 return 0;
447 }
448
449 if (script->v.binary_read_metadata == NULL)
450 return 1;
451
452 return script->v.binary_read_metadata(script, sblock, offset);
453 }
454
sieve_script_binary_write_metadata(struct sieve_script * script,struct sieve_binary_block * sblock)455 void sieve_script_binary_write_metadata(struct sieve_script *script,
456 struct sieve_binary_block *sblock)
457 {
458 sieve_binary_emit_cstring(sblock, script->driver_name);
459 sieve_binary_emit_unsigned(sblock, script->storage->version);
460 sieve_binary_emit_cstring(sblock, (script->location == NULL ?
461 "" : script->location));
462
463 if (script->v.binary_write_metadata == NULL)
464 return;
465
466 script->v.binary_write_metadata(script, sblock);
467 }
468
sieve_script_binary_dump_metadata(struct sieve_script * script,struct sieve_dumptime_env * denv,struct sieve_binary_block * sblock,sieve_size_t * offset)469 bool sieve_script_binary_dump_metadata(struct sieve_script *script,
470 struct sieve_dumptime_env *denv,
471 struct sieve_binary_block *sblock,
472 sieve_size_t *offset)
473 {
474 struct sieve_binary *sbin = sieve_binary_block_get_binary(sblock);
475 struct sieve_instance *svinst = sieve_binary_svinst(sbin);
476 string_t *storage_class, *location;
477 struct sieve_script *adhoc_script = NULL;
478 unsigned int version;
479 bool result = TRUE;
480
481 /* storage class */
482 if (!sieve_binary_read_string(sblock, offset, &storage_class))
483 return FALSE;
484 sieve_binary_dumpf(denv, "class = %s\n", str_c(storage_class));
485
486 /* version */
487 if (!sieve_binary_read_unsigned(sblock, offset, &version))
488 return FALSE;
489 sieve_binary_dumpf(denv, "class.version = %d\n", version);
490
491 /* location */
492 if (!sieve_binary_read_string(sblock, offset, &location))
493 return FALSE;
494 sieve_binary_dumpf(denv, "location = %s\n", str_c(location));
495
496 if (script == NULL) {
497 script = adhoc_script =
498 sieve_script_create(svinst, str_c(location),
499 NULL, NULL);
500 }
501
502 if (script != NULL && script->v.binary_dump_metadata != NULL) {
503 result = script->v.binary_dump_metadata(
504 script, denv, sblock, offset);
505 }
506
507 if (adhoc_script != NULL)
508 sieve_script_unref(&adhoc_script);
509 return result;
510 }
511
512 struct sieve_binary *
sieve_script_binary_load(struct sieve_script * script,enum sieve_error * error_r)513 sieve_script_binary_load(struct sieve_script *script, enum sieve_error *error_r)
514 {
515 if (script->v.binary_load == NULL) {
516 *error_r = SIEVE_ERROR_NOT_POSSIBLE;
517 return NULL;
518 }
519
520 return script->v.binary_load(script, error_r);
521 }
522
sieve_script_binary_save(struct sieve_script * script,struct sieve_binary * sbin,bool update,enum sieve_error * error_r)523 int sieve_script_binary_save(struct sieve_script *script,
524 struct sieve_binary *sbin, bool update,
525 enum sieve_error *error_r)
526 {
527 struct sieve_script *bin_script = sieve_binary_script(sbin);
528 enum sieve_error error;
529
530 if (error_r != NULL)
531 *error_r = SIEVE_ERROR_NONE;
532 else
533 error_r = &error;
534
535 i_assert(bin_script == NULL || sieve_script_equals(bin_script, script));
536
537 if (script->v.binary_save == NULL) {
538 *error_r = SIEVE_ERROR_NOT_POSSIBLE;
539 return -1;
540 }
541
542 return script->v.binary_save(script, sbin, update, error_r);
543 }
544
sieve_script_binary_get_prefix(struct sieve_script * script)545 const char *sieve_script_binary_get_prefix(struct sieve_script *script)
546 {
547 struct sieve_storage *storage = script->storage;
548
549 if (storage->bin_dir != NULL &&
550 sieve_storage_setup_bindir(storage, 0700) >= 0) {
551 return t_strconcat(storage->bin_dir, "/", script->name, NULL);
552 }
553
554 if (script->v.binary_get_prefix == NULL)
555 return NULL;
556
557 return script->v.binary_get_prefix(script);
558 }
559
560 /*
561 * Management
562 */
563
564 static int
sieve_script_copy_from_default(struct sieve_script * script,const char * newname)565 sieve_script_copy_from_default(struct sieve_script *script, const char *newname)
566 {
567 struct sieve_storage *storage = script->storage;
568 struct istream *input;
569 int ret;
570
571 /* copy from default */
572 if ((ret = sieve_script_open(script, NULL)) < 0 ||
573 (ret = sieve_script_get_stream(script, &input, NULL)) < 0) {
574 sieve_storage_copy_error(storage->default_for, storage);
575 return ret;
576 }
577
578 ret = sieve_storage_save_as(storage->default_for, input, newname);
579 if (ret < 0) {
580 sieve_storage_copy_error(storage, storage->default_for);
581 } else if (sieve_script_is_active(script) > 0) {
582 struct sieve_script *newscript;
583 enum sieve_error error;
584
585 newscript = sieve_storage_open_script(storage->default_for,
586 newname, &error);
587 if (newscript == NULL) {
588 /* Somehow not actually saved */
589 ret = (error == SIEVE_ERROR_NOT_FOUND ? 0 : -1);
590 } else if (sieve_script_activate(newscript, (time_t)-1) < 0) {
591 /* Failed to activate; roll back */
592 ret = -1;
593 (void)sieve_script_delete(newscript, TRUE);
594 }
595 if (newscript != NULL)
596 sieve_script_unref(&newscript);
597
598 if (ret < 0) {
599 e_error(storage->event,
600 "Failed to implicitly activate script `%s' "
601 "after rename", newname);
602 sieve_storage_copy_error(storage->default_for, storage);
603 }
604 }
605
606 return ret;
607 }
608
sieve_script_rename(struct sieve_script * script,const char * newname)609 int sieve_script_rename(struct sieve_script *script, const char *newname)
610 {
611 struct sieve_storage *storage = script->storage;
612 const char *oldname = script->name;
613 struct event_passthrough *event;
614 int ret;
615
616 i_assert(newname != NULL);
617
618 /* Check script name */
619 if (!sieve_script_name_is_valid(newname)) {
620 sieve_script_set_error(script,
621 SIEVE_ERROR_BAD_PARAMS,
622 "Invalid new Sieve script name `%s'.",
623 str_sanitize(newname, 80));
624 return -1;
625 }
626
627 i_assert(script->open); // FIXME: auto-open?
628
629 if (storage->default_for == NULL) {
630 i_assert((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
631
632 /* rename script */
633 i_assert(script->v.rename != NULL);
634 ret = script->v.rename(script, newname);
635
636 /* rename INBOX mailbox attribute */
637 if (ret >= 0 && oldname != NULL) {
638 (void)sieve_storage_sync_script_rename(storage, oldname,
639 newname);
640 }
641 } else if (sieve_storage_check_script(storage->default_for,
642 newname, NULL) > 0) {
643 sieve_script_set_error(script, SIEVE_ERROR_EXISTS,
644 "A sieve script with that name already exists.");
645 sieve_storage_copy_error(storage->default_for, storage);
646 ret = -1;
647 } else {
648 ret = sieve_script_copy_from_default(script, newname);
649 }
650
651 event = event_create_passthrough(script->event)->
652 clear_field("script_name")->
653 add_str("old_script_name", script->name)->
654 add_str("new_script_name", newname)->
655 set_name("sieve_script_renamed");
656
657 if (ret >= 0) {
658 e_debug(event->event(), "Script renamed to `%s'", newname);
659 } else {
660 event = event->add_str("error", storage->error);
661
662 e_debug(event->event(), "Failed to rename script: %s",
663 storage->error);
664 }
665
666 return ret;
667 }
668
sieve_script_delete(struct sieve_script * script,bool ignore_active)669 int sieve_script_delete(struct sieve_script *script, bool ignore_active)
670 {
671 struct sieve_storage *storage = script->storage;
672 bool is_active = FALSE;
673 int ret = 0;
674
675 i_assert(script->open); // FIXME: auto-open?
676
677 /* Is the requested script active? */
678 if (sieve_script_is_active(script) > 0) {
679 is_active = TRUE;
680 if (!ignore_active) {
681 sieve_script_set_error(script, SIEVE_ERROR_ACTIVE,
682 "Cannot delete the active Sieve script.");
683 if (storage->default_for != NULL) {
684 sieve_storage_copy_error(storage->default_for,
685 storage);
686 }
687 return -1;
688 }
689 }
690
691 /* Trying to delete the default script? */
692 if (storage->is_default) {
693 /* ignore */
694 return 0;
695 }
696
697 i_assert((script->storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
698
699 /* Deactivate it explicity */
700 if (ignore_active && is_active)
701 (void)sieve_storage_deactivate(storage, (time_t)-1);
702
703 i_assert(script->v.delete != NULL);
704 ret = script->v.delete(script);
705
706 if (ret >= 0) {
707 struct event_passthrough *e =
708 event_create_passthrough(script->event)->
709 set_name("sieve_script_deleted");
710 e_debug(e->event(), "Script deleted");
711
712 /* unset INBOX mailbox attribute */
713 (void)sieve_storage_sync_script_delete(storage, script->name);
714 } else {
715 struct event_passthrough *e =
716 event_create_passthrough(script->event)->
717 add_str("error", storage->error)->
718 set_name("sieve_script_deleted");
719 e_debug(e->event(), "Failed to delete script: %s",
720 storage->error);
721 }
722 return ret;
723 }
724
sieve_script_is_active(struct sieve_script * script)725 int sieve_script_is_active(struct sieve_script *script)
726 {
727 struct sieve_storage *storage = script->storage;
728
729 /* Special handling if this is a default script */
730 if (storage->default_for != NULL) {
731 int ret = sieve_storage_active_script_is_default(
732 storage->default_for);
733 if (ret < 0)
734 sieve_storage_copy_error(storage, storage->default_for);
735 return ret;
736 }
737
738 if (script->v.is_active == NULL)
739 return 0;
740 return script->v.is_active(script);
741 }
742
sieve_script_activate(struct sieve_script * script,time_t mtime)743 int sieve_script_activate(struct sieve_script *script, time_t mtime)
744 {
745 struct sieve_storage *storage = script->storage;
746 int ret = 0;
747
748 i_assert(script->open); // FIXME: auto-open?
749
750 if (storage->default_for == NULL) {
751 i_assert((storage->flags & SIEVE_STORAGE_FLAG_READWRITE) != 0);
752
753 i_assert(script->v.activate != NULL);
754 ret = script->v.activate(script);
755
756 if (ret >= 0) {
757 struct event_passthrough *e =
758 event_create_passthrough(script->event)->
759 set_name("sieve_script_activated");
760 e_debug(e->event(), "Script activated");
761
762 sieve_storage_set_modified(storage, mtime);
763 (void)sieve_storage_sync_script_activate(storage);
764 } else {
765 struct event_passthrough *e =
766 event_create_passthrough(script->event)->
767 add_str("error", storage->error)->
768 set_name("sieve_script_activated");
769 e_debug(e->event(), "Failed to activate script: %s",
770 storage->error);
771 }
772
773 } else {
774 /* Activating the default script is equal to deactivating
775 the storage */
776 ret = sieve_storage_deactivate(storage->default_for,
777 (time_t)-1);
778 if (ret < 0)
779 sieve_storage_copy_error(storage, storage->default_for);
780 }
781
782 return ret;
783 }
784
785 /*
786 * Error handling
787 */
788
sieve_script_set_error(struct sieve_script * script,enum sieve_error error,const char * fmt,...)789 void sieve_script_set_error(struct sieve_script *script, enum sieve_error error,
790 const char *fmt, ...)
791 {
792 struct sieve_storage *storage = script->storage;
793 va_list va;
794
795 sieve_storage_clear_error(storage);
796
797 if (fmt != NULL) {
798 va_start(va, fmt);
799 storage->error = i_strdup_vprintf(fmt, va);
800 va_end(va);
801 }
802 storage->error_code = error;
803 }
804
sieve_script_set_internal_error(struct sieve_script * script)805 void sieve_script_set_internal_error(struct sieve_script *script)
806 {
807 sieve_storage_set_internal_error(script->storage);
808 }
809
sieve_script_set_critical(struct sieve_script * script,const char * fmt,...)810 void sieve_script_set_critical(struct sieve_script *script,
811 const char *fmt, ...)
812 {
813 struct sieve_storage *storage = script->storage;
814
815 va_list va;
816
817 if (fmt != NULL) {
818 if ((storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0) {
819 va_start(va, fmt);
820 e_error(script->event, "%s", t_strdup_vprintf(fmt, va));
821 va_end(va);
822
823 sieve_storage_set_internal_error(storage);
824
825 } else {
826 sieve_storage_clear_error(storage);
827
828 /* no user is involved while synchronizing, so do it the
829 normal way */
830 va_start(va, fmt);
831 storage->error = i_strdup_vprintf(fmt, va);
832 va_end(va);
833
834 storage->error_code = SIEVE_ERROR_TEMP_FAILURE;
835 }
836 }
837 }
838
839 const char *
sieve_script_get_last_error(struct sieve_script * script,enum sieve_error * error_r)840 sieve_script_get_last_error(struct sieve_script *script,
841 enum sieve_error *error_r)
842 {
843 return sieve_storage_get_last_error(script->storage, error_r);
844 }
845
sieve_script_get_last_error_lcase(struct sieve_script * script)846 const char *sieve_script_get_last_error_lcase(struct sieve_script *script)
847 {
848 return sieve_error_from_external(script->storage->error);
849 }
850
851 /*
852 * Script sequence
853 */
854
sieve_script_sequence_init(struct sieve_script_sequence * seq,struct sieve_storage * storage)855 void sieve_script_sequence_init(struct sieve_script_sequence *seq,
856 struct sieve_storage *storage)
857 {
858 seq->storage = storage;
859 sieve_storage_ref(storage);
860 }
861
862 struct sieve_script_sequence *
sieve_script_sequence_create(struct sieve_instance * svinst,const char * location,enum sieve_error * error_r)863 sieve_script_sequence_create(struct sieve_instance *svinst,
864 const char *location, enum sieve_error *error_r)
865 {
866 struct sieve_storage *storage;
867 struct sieve_script_sequence *seq;
868 enum sieve_error error;
869
870 if (error_r != NULL)
871 *error_r = SIEVE_ERROR_NONE;
872 else
873 error_r = &error;
874
875 storage = sieve_storage_create(svinst, location, 0, error_r);
876 if (storage == NULL)
877 return NULL;
878
879 seq = sieve_storage_get_script_sequence(storage, error_r);
880
881 sieve_storage_unref(&storage);
882 return seq;
883 }
884
885 struct sieve_script *
sieve_script_sequence_next(struct sieve_script_sequence * seq,enum sieve_error * error_r)886 sieve_script_sequence_next(struct sieve_script_sequence *seq,
887 enum sieve_error *error_r)
888 {
889 struct sieve_storage *storage = seq->storage;
890
891 i_assert(storage->v.script_sequence_next != NULL);
892 return storage->v.script_sequence_next(seq, error_r);
893 }
894
sieve_script_sequence_free(struct sieve_script_sequence ** _seq)895 void sieve_script_sequence_free(struct sieve_script_sequence **_seq)
896 {
897 struct sieve_script_sequence *seq = *_seq;
898 struct sieve_storage *storage = seq->storage;
899
900 if (storage->v.script_sequence_destroy != NULL)
901 storage->v.script_sequence_destroy(seq);
902
903 sieve_storage_unref(&storage);
904 *_seq = NULL;
905 }
906
907