summaryrefslogtreecommitdiffstats
path: root/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-script.c
diff options
context:
space:
mode:
Diffstat (limited to 'pigeonhole/src/lib-sieve/storage/dict/sieve-dict-script.c')
-rw-r--r--pigeonhole/src/lib-sieve/storage/dict/sieve-dict-script.c343
1 files changed, 343 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-script.c b/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-script.c
new file mode 100644
index 0000000..eb28f7d
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/storage/dict/sieve-dict-script.c
@@ -0,0 +1,343 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "strfuncs.h"
+#include "istream.h"
+#include "dict.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-dump.h"
+#include "sieve-binary.h"
+
+#include "sieve-dict-storage.h"
+
+/*
+ * Script dict implementation
+ */
+
+static struct sieve_dict_script *sieve_dict_script_alloc(void)
+{
+ struct sieve_dict_script *dscript;
+ pool_t pool;
+
+ pool = pool_alloconly_create("sieve_dict_script", 1024);
+ dscript = p_new(pool, struct sieve_dict_script, 1);
+ dscript->script = sieve_dict_script;
+ dscript->script.pool = pool;
+
+ return dscript;
+}
+
+struct sieve_dict_script *sieve_dict_script_init
+(struct sieve_dict_storage *dstorage, const char *name)
+{
+ struct sieve_storage *storage = &dstorage->storage;
+ struct sieve_dict_script *dscript = NULL;
+ const char *location;
+
+ if ( name == NULL ) {
+ name = SIEVE_DICT_SCRIPT_DEFAULT;
+ location = storage->location;
+ } else {
+ location = t_strconcat
+ (storage->location, ";name=", name, NULL);
+ }
+
+ dscript = sieve_dict_script_alloc();
+ sieve_script_init(&dscript->script,
+ storage, &sieve_dict_script, location, name);
+
+ return dscript;
+}
+
+static void sieve_dict_script_destroy(struct sieve_script *script)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+
+ if ( dscript->data_pool != NULL )
+ pool_unref(&dscript->data_pool);
+}
+
+static int sieve_dict_script_open
+(struct sieve_script *script, enum sieve_error *error_r)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+ struct sieve_storage *storage = script->storage;
+ struct sieve_dict_storage *dstorage =
+ (struct sieve_dict_storage *)storage;
+ const char *name = script->name;
+ const char *path, *data_id, *error;
+ int ret;
+
+ if ( sieve_dict_storage_get_dict
+ (dstorage, &dscript->dict, error_r) < 0 )
+ return -1;
+
+ path = t_strconcat
+ (DICT_SIEVE_NAME_PATH, dict_escape_string(name), NULL);
+
+ struct dict_op_settings set = {
+ .username = dstorage->username,
+ };
+ ret = dict_lookup
+ (dscript->dict, &set, script->pool, path, &data_id, &error);
+ if ( ret <= 0 ) {
+ if ( ret < 0 ) {
+ sieve_script_set_critical(script,
+ "Failed to lookup script id from path %s: %s", path, error);
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ } else {
+ e_debug(script->event,
+ "Script `%s' not found at path %s", name, path);
+ sieve_script_set_error(script,
+ SIEVE_ERROR_NOT_FOUND,
+ "Sieve script `%s' not found", name);
+ *error_r = SIEVE_ERROR_NOT_FOUND;
+ }
+ return -1;
+ }
+
+ dscript->data_id = p_strdup(script->pool, data_id);
+ return 0;
+}
+
+static int sieve_dict_script_get_stream
+(struct sieve_script *script, struct istream **stream_r,
+ enum sieve_error *error_r)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+ struct sieve_dict_storage *dstorage =
+ (struct sieve_dict_storage *)script->storage;
+ const char *path, *name = script->name, *data, *error;
+ int ret;
+
+ dscript->data_pool =
+ pool_alloconly_create("sieve_dict_script data pool", 1024);
+
+ path = t_strconcat
+ (DICT_SIEVE_DATA_PATH, dict_escape_string(dscript->data_id), NULL);
+
+ struct dict_op_settings set = {
+ .username = dstorage->username,
+ };
+ ret = dict_lookup
+ (dscript->dict, &set, dscript->data_pool, path, &data, &error);
+ if ( ret <= 0 ) {
+ if ( ret < 0 ) {
+ sieve_script_set_critical(script,
+ "Failed to lookup data with id `%s' "
+ "for script `%s' from path %s: %s",
+ dscript->data_id, name, path, error);
+ } else {
+ sieve_script_set_critical(script,
+ "Data with id `%s' for script `%s' "
+ "not found at path %s",
+ dscript->data_id, name, path);
+ }
+ *error_r = SIEVE_ERROR_TEMP_FAILURE;
+ return -1;
+ }
+
+ dscript->data = p_strdup(script->pool, data);
+ *stream_r = i_stream_create_from_data(dscript->data, strlen(dscript->data));
+ return 0;
+}
+
+static int sieve_dict_script_binary_read_metadata
+(struct sieve_script *script, struct sieve_binary_block *sblock,
+ sieve_size_t *offset)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+ struct sieve_binary *sbin =
+ sieve_binary_block_get_binary(sblock);
+ string_t *data_id;
+
+ if ( dscript->data_id == NULL &&
+ sieve_script_open(script, NULL) < 0 )
+ return 0;
+
+ if ( !sieve_binary_read_string(sblock, offset, &data_id) ) {
+ e_error(script->event,
+ "Binary `%s' has invalid metadata for script `%s'",
+ sieve_binary_path(sbin), sieve_script_location(script));
+ return -1;
+ }
+ i_assert( dscript->data_id != NULL );
+ if ( strcmp(str_c(data_id), dscript->data_id) != 0 ) {
+ e_debug(script->event,
+ "Binary `%s' reports different data ID for script `%s' "
+ "(`%s' rather than `%s')",
+ sieve_binary_path(sbin), sieve_script_location(script),
+ str_c(data_id), dscript->data_id);
+ return 0;
+ }
+ return 1;
+}
+
+static void sieve_dict_script_binary_write_metadata
+(struct sieve_script *script, struct sieve_binary_block *sblock)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+
+ sieve_binary_emit_cstring(sblock, dscript->data_id);
+}
+
+static bool sieve_dict_script_binary_dump_metadata
+(struct sieve_script *script ATTR_UNUSED, struct sieve_dumptime_env *denv,
+ struct sieve_binary_block *sblock, sieve_size_t *offset)
+{
+ string_t *data_id;
+
+ if ( !sieve_binary_read_string(sblock, offset, &data_id) )
+ return FALSE;
+ sieve_binary_dumpf(denv, "dict.data_id = %s\n", str_c(data_id));
+
+ return TRUE;
+}
+
+static const char * sieve_dict_script_get_binpath
+(struct sieve_dict_script *dscript)
+{
+ struct sieve_script *script = &dscript->script;
+ struct sieve_storage *storage = script->storage;
+
+ if ( dscript->binpath == NULL ) {
+ if ( storage->bin_dir == NULL )
+ return NULL;
+ dscript->binpath = p_strconcat(script->pool,
+ storage->bin_dir, "/",
+ sieve_binfile_from_name(script->name), NULL);
+ }
+
+ return dscript->binpath;
+}
+
+static struct sieve_binary *sieve_dict_script_binary_load
+(struct sieve_script *script, enum sieve_error *error_r)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+
+ if ( sieve_dict_script_get_binpath(dscript) == NULL )
+ return NULL;
+
+ return sieve_binary_open(script->storage->svinst,
+ dscript->binpath, script, error_r);
+}
+
+static int sieve_dict_script_binary_save
+(struct sieve_script *script, struct sieve_binary *sbin, bool update,
+ enum sieve_error *error_r)
+{
+ struct sieve_dict_script *dscript =
+ (struct sieve_dict_script *)script;
+
+ if ( sieve_dict_script_get_binpath(dscript) == NULL )
+ return 0;
+ if ( sieve_storage_setup_bindir(script->storage, 0700) < 0 )
+ return -1;
+
+ return sieve_binary_save(sbin,
+ dscript->binpath, update, 0600, error_r);
+}
+
+static bool sieve_dict_script_equals
+(const struct sieve_script *script, const struct sieve_script *other)
+{
+ struct sieve_storage *storage = script->storage;
+ struct sieve_storage *sother = other->storage;
+
+ if ( strcmp(storage->location, sother->location) != 0 )
+ return FALSE;
+
+ i_assert( script->name != NULL && other->name != NULL );
+
+ return ( strcmp(script->name, other->name) == 0 );
+}
+
+const struct sieve_script sieve_dict_script = {
+ .driver_name = SIEVE_DICT_STORAGE_DRIVER_NAME,
+ .v = {
+ .destroy = sieve_dict_script_destroy,
+
+ .open = sieve_dict_script_open,
+
+ .get_stream = sieve_dict_script_get_stream,
+
+ .binary_read_metadata =sieve_dict_script_binary_read_metadata,
+ .binary_write_metadata = sieve_dict_script_binary_write_metadata,
+ .binary_dump_metadata = sieve_dict_script_binary_dump_metadata,
+ .binary_load = sieve_dict_script_binary_load,
+ .binary_save = sieve_dict_script_binary_save,
+
+ .equals = sieve_dict_script_equals
+ }
+};
+
+/*
+ * Script sequence
+ */
+
+struct sieve_dict_script_sequence {
+ struct sieve_script_sequence seq;
+
+ bool done:1;
+};
+
+struct sieve_script_sequence *sieve_dict_storage_get_script_sequence
+(struct sieve_storage *storage, enum sieve_error *error_r)
+{
+ struct sieve_dict_script_sequence *dseq = NULL;
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
+
+ /* Create sequence object */
+ dseq = i_new(struct sieve_dict_script_sequence, 1);
+ sieve_script_sequence_init(&dseq->seq, storage);
+
+ return &dseq->seq;
+}
+
+struct sieve_script *sieve_dict_script_sequence_next
+(struct sieve_script_sequence *seq, enum sieve_error *error_r)
+{
+ struct sieve_dict_script_sequence *dseq =
+ (struct sieve_dict_script_sequence *)seq;
+ struct sieve_dict_storage *dstorage =
+ (struct sieve_dict_storage *)seq->storage;
+ struct sieve_dict_script *dscript;
+
+ if ( error_r != NULL )
+ *error_r = SIEVE_ERROR_NONE;
+
+ if ( dseq->done )
+ return NULL;
+ dseq->done = TRUE;
+
+ dscript = sieve_dict_script_init
+ (dstorage, seq->storage->script_name);
+ if ( sieve_script_open(&dscript->script, error_r) < 0 ) {
+ struct sieve_script *script = &dscript->script;
+ sieve_script_unref(&script);
+ return NULL;
+ }
+
+ return &dscript->script;
+}
+
+void sieve_dict_script_sequence_destroy(struct sieve_script_sequence *seq)
+{
+ struct sieve_dict_script_sequence *dseq =
+ (struct sieve_dict_script_sequence *)seq;
+ i_free(dseq);
+}
+