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