/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "str-sanitize.h" #include "home-expand.h" #include "eacces-error.h" #include "mkdir-parents.h" #include "ioloop.h" #include "sieve-common.h" #include "sieve-settings.h" #include "sieve-error-private.h" #include "sieve-script-private.h" #include "sieve-storage-private.h" #include #include #include #include #include #define CRITICAL_MSG \ "Internal error occurred. Refer to server log for more information." #define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]" struct event_category event_category_sieve_storage = { .parent = &event_category_sieve, .name = "sieve-storage", }; /* * Storage class */ struct sieve_storage_class_registry { ARRAY_TYPE(sieve_storage_class) storage_classes; }; void sieve_storages_init(struct sieve_instance *svinst) { svinst->storage_reg = p_new(svinst->pool, struct sieve_storage_class_registry, 1); p_array_init(&svinst->storage_reg->storage_classes, svinst->pool, 8); sieve_storage_class_register(svinst, &sieve_file_storage); sieve_storage_class_register(svinst, &sieve_dict_storage); sieve_storage_class_register(svinst, &sieve_ldap_storage); } void sieve_storages_deinit(struct sieve_instance *svinst ATTR_UNUSED) { /* nothing yet */ } void sieve_storage_class_register(struct sieve_instance *svinst, const struct sieve_storage *storage_class) { struct sieve_storage_class_registry *reg = svinst->storage_reg; const struct sieve_storage *old_class; old_class = sieve_storage_find_class(svinst, storage_class->driver_name); if (old_class != NULL) { if (old_class->v.alloc == NULL) { /* replacing a "support not compiled in" storage class */ sieve_storage_class_unregister(svinst, old_class); } else { i_panic("sieve_storage_class_register(%s): " "Already registered", storage_class->driver_name); } } array_append(®->storage_classes, &storage_class, 1); } void sieve_storage_class_unregister(struct sieve_instance *svinst, const struct sieve_storage *storage_class) { struct sieve_storage_class_registry *reg = svinst->storage_reg; const struct sieve_storage *const *classes; unsigned int i, count; classes = array_get(®->storage_classes, &count); for (i = 0; i < count; i++) { if (classes[i] == storage_class) { array_delete(®->storage_classes, i, 1); break; } } } const struct sieve_storage * sieve_storage_find_class(struct sieve_instance *svinst, const char *name) { struct sieve_storage_class_registry *reg = svinst->storage_reg; const struct sieve_storage *const *classes; unsigned int i, count; i_assert(name != NULL); classes = array_get(®->storage_classes, &count); for (i = 0; i < count; i++) { if (strcasecmp(classes[i]->driver_name, name) == 0) return classes[i]; } return NULL; } /* * Storage instance */ static const char *split_next_arg(const char *const **_args) { const char *const *args = *_args; const char *str = args[0]; /* join arguments for escaped ";" separator */ args++; while (*args != NULL && **args == '\0') { args++; if (*args == NULL) { /* string ends with ";", just ignore it. */ break; } str = t_strconcat(str, ";", *args, NULL); args++; } *_args = args; return str; } static int sieve_storage_driver_parse(struct sieve_instance *svinst, const char **data, const struct sieve_storage **driver_r) { const struct sieve_storage *storage_class = NULL; const char *p; p = strchr(*data, ':'); if (p == NULL) return 0; /* Lookup storage driver */ T_BEGIN { const char *driver; driver = t_strdup_until(*data, p); *data = p+1; storage_class = sieve_storage_find_class(svinst, driver); if (storage_class == NULL) { e_error(svinst->event, "Unknown storage driver module `%s'", driver); } else if (storage_class->v.alloc == NULL) { e_error(svinst->event, "Support not compiled in for storage driver `%s'", driver); storage_class = NULL; } } T_END; *driver_r = storage_class; return (storage_class == NULL ? -1 : 1); } static int sieve_storage_data_parse(struct sieve_storage *storage, const char *data, const char **location_r, const char *const **options_r) { ARRAY_TYPE(const_string) options; const char *const *tmp; if (*data == '\0') { *options_r = NULL; *location_r = data; return 0; } /* */ tmp = t_strsplit(data, ";"); *location_r = split_next_arg(&tmp); if (options_r != NULL) { t_array_init(&options, 8); /* [