diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/storage/file/sieve-file-script-sequence.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/storage/file/sieve-file-script-sequence.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/storage/file/sieve-file-script-sequence.c b/pigeonhole/src/lib-sieve/storage/file/sieve-file-script-sequence.c new file mode 100644 index 0000000..a1ae75d --- /dev/null +++ b/pigeonhole/src/lib-sieve/storage/file/sieve-file-script-sequence.c @@ -0,0 +1,244 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" +#include "array.h" +#include "eacces-error.h" + +#include "sieve-common.h" +#include "sieve-script-private.h" + +#include "sieve-file-storage.h" + +#include <stdio.h> +#include <dirent.h> + +/* + * Script sequence + */ + +struct sieve_file_script_sequence { + struct sieve_script_sequence seq; + pool_t pool; + + ARRAY_TYPE(const_string) script_files; + unsigned int index; + + bool storage_is_file:1; +}; + +static int sieve_file_script_sequence_read_dir +(struct sieve_file_script_sequence *fseq, const char *path) +{ + struct sieve_storage *storage = fseq->seq.storage; + DIR *dirp; + int ret = 0; + + /* Open the directory */ + if ( (dirp = opendir(path)) == NULL ) { + switch ( errno ) { + case ENOENT: + sieve_storage_set_error(storage, + SIEVE_ERROR_NOT_FOUND, + "Script sequence location not found"); + break; + case EACCES: + sieve_storage_set_error(storage, + SIEVE_ERROR_NO_PERMISSION, + "Script sequence location not accessible"); + e_error(storage->event, + "Failed to open sieve sequence: %s", + eacces_error_get("stat", path)); + break; + default: + sieve_storage_set_critical(storage, + "Failed to open sieve sequence: " + "opendir(%s) failed: %m", path); + break; + } + return -1; + } + + /* Read and sort script files */ + for (;;) { + const char *const *files; + unsigned int count, i; + const char *file; + struct dirent *dp; + struct stat st; + + errno = 0; + if ( (dp=readdir(dirp)) == NULL ) + break; + + if ( !sieve_script_file_has_extension(dp->d_name) ) + continue; + + file = NULL; + T_BEGIN { + if ( path[strlen(path)-1] == '/' ) + file = t_strconcat(path, dp->d_name, NULL); + else + file = t_strconcat(path, "/", dp->d_name, NULL); + + if ( stat(file, &st) == 0 && S_ISREG(st.st_mode) ) + file = p_strdup(fseq->pool, dp->d_name); + else + file = NULL; + } T_END; + + if (file == NULL) + continue; + + /* Insert into sorted array */ + files = array_get(&fseq->script_files, &count); + for ( i = 0; i < count; i++ ) { + if ( strcmp(file, files[i]) < 0 ) + break; + } + + if ( i == count ) + array_append(&fseq->script_files, &file, 1); + else + array_insert(&fseq->script_files, i, &file, 1); + } + + if ( errno != 0 ) { + sieve_storage_set_critical(storage, + "Failed to read sequence directory: " + "readdir(%s) failed: %m", path); + ret = -1; + } + + /* Close the directory */ + if ( dirp != NULL && closedir(dirp) < 0 ) { + e_error(storage->event, + "Failed to close sequence directory: " + "closedir(%s) failed: %m", path); + } + return ret; +} + +struct sieve_script_sequence *sieve_file_storage_get_script_sequence +(struct sieve_storage *storage, enum sieve_error *error_r) +{ + struct sieve_file_storage *fstorage = + (struct sieve_file_storage *)storage; + struct sieve_file_script_sequence *fseq = NULL; + const char *name = storage->script_name; + const char *file; + pool_t pool; + struct stat st; + + /* Specified path can either be a regular file or a directory */ + if ( stat(fstorage->path, &st) != 0 ) { + switch ( errno ) { + case ENOENT: + sieve_storage_set_error(storage, + SIEVE_ERROR_NOT_FOUND, + "Script sequence location not found"); + break; + case EACCES: + sieve_storage_set_error(storage, + SIEVE_ERROR_NO_PERMISSION, + "Script sequence location not accessible"); + e_error(storage->event, + "Failed to open sieve sequence: %s", + eacces_error_get("stat", fstorage->path)); + break; + default: + sieve_storage_set_critical(storage, + "Failed to open sieve sequence: " + "stat(%s) failed: %m", fstorage->path); + break; + } + *error_r = storage->error_code; + return NULL; + } + + /* Create sequence object */ + pool = pool_alloconly_create("sieve_file_script_sequence", 1024); + fseq = p_new(pool, struct sieve_file_script_sequence, 1); + fseq->pool = pool; + sieve_script_sequence_init(&fseq->seq, storage); + + if ( S_ISDIR(st.st_mode) ) { + i_array_init(&fseq->script_files, 16); + + /* Path is directory */ + if (name == 0 || *name == '\0') { + /* Read all '.sieve' files in directory */ + if (sieve_file_script_sequence_read_dir + (fseq, fstorage->path) < 0) { + *error_r = storage->error_code; + sieve_file_script_sequence_destroy(&fseq->seq); + return NULL; + } + + } else { + /* Read specific script file */ + file = sieve_script_file_from_name(name); + file = p_strdup(pool, file); + array_append(&fseq->script_files, &file, 1); + } + + } else { + /* Path is a file + (apparently; we'll see about that once it is opened) */ + fseq->storage_is_file = TRUE; + } + + return &fseq->seq; +} + +struct sieve_script *sieve_file_script_sequence_next +(struct sieve_script_sequence *seq, enum sieve_error *error_r) +{ + struct sieve_file_script_sequence *fseq = + (struct sieve_file_script_sequence *)seq; + struct sieve_file_storage *fstorage = + (struct sieve_file_storage *)seq->storage; + struct sieve_file_script *fscript; + const char *const *files; + unsigned int count; + + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NONE; + + fscript = NULL; + if ( fseq->storage_is_file ) { + if ( fseq->index++ < 1 ) + fscript = sieve_file_script_open_from_name(fstorage, NULL); + + } else { + files = array_get(&fseq->script_files, &count); + + while ( fseq->index < count ) { + fscript = sieve_file_script_open_from_filename + (fstorage, files[fseq->index++], NULL); + if (fscript != NULL) + break; + if (seq->storage->error_code != SIEVE_ERROR_NOT_FOUND) + break; + sieve_storage_clear_error(seq->storage); + } + } + + if (fscript == NULL ) { + if ( error_r != NULL ) + *error_r = seq->storage->error_code; + return NULL; + } + return &fscript->script; +} + +void sieve_file_script_sequence_destroy(struct sieve_script_sequence *seq) +{ + struct sieve_file_script_sequence *fseq = + (struct sieve_file_script_sequence *)seq; + + if ( array_is_created(&fseq->script_files) ) + array_free(&fseq->script_files); + pool_unref(&fseq->pool); +} |