diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/util/mail-raw.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/util/mail-raw.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/util/mail-raw.c b/pigeonhole/src/lib-sieve/util/mail-raw.c new file mode 100644 index 0000000..b357fe1 --- /dev/null +++ b/pigeonhole/src/lib-sieve/util/mail-raw.c @@ -0,0 +1,247 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "istream.h" +#include "istream-seekable.h" +#include "str.h" +#include "str-sanitize.h" +#include "strescape.h" +#include "safe-mkstemp.h" +#include "path-util.h" +#include "message-address.h" +#include "mbox-from.h" +#include "raw-storage.h" +#include "mail-namespace.h" +#include "master-service.h" +#include "master-service-settings.h" +#include "settings-parser.h" +#include "mail-raw.h" + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <pwd.h> + +/* + * Configuration + */ + +#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON" + +/* After buffer grows larger than this, create a temporary file to /tmp + where to read the mail. */ +#define MAIL_MAX_MEMORY_BUFFER (1024*128) + +static const char *wanted_headers[] = { + "From", "Message-ID", "Subject", "Return-Path", + NULL +}; + +/* + * Global data + */ + +struct mail_raw_user { + struct mail_namespace *ns; + struct mail_user *mail_user; +}; + +/* + * Raw mail implementation + */ + +static int seekable_fd_callback +(const char **path_r, void *context) +{ + struct mail_user *ruser = (struct mail_user *)context; + string_t *path; + int fd; + + path = t_str_new(128); + mail_user_set_get_temp_prefix(path, ruser->set); + fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1); + if (fd == -1) { + i_error("safe_mkstemp(%s) failed: %m", str_c(path)); + return -1; + } + + /* we just want the fd, unlink it */ + if (i_unlink(str_c(path)) < 0) { + /* shouldn't happen.. */ + i_close_fd(&fd); + return -1; + } + + *path_r = str_c(path); + return fd; +} + +static struct istream *mail_raw_create_stream +(struct mail_user *ruser, int fd, time_t *mtime_r, const char **sender) +{ + struct istream *input, *input2, *input_list[2]; + const unsigned char *data; + size_t i, size; + int ret, tz; + char *env_sender = NULL; + + *mtime_r = (time_t)-1; + fd_set_nonblock(fd, FALSE); + + input = i_stream_create_fd(fd, 4096); + input->blocking = TRUE; + /* If input begins with a From-line, drop it */ + ret = i_stream_read_bytes(input, &data, &size, 5); + if (ret > 0 && memcmp(data, "From ", 5) == 0) { + /* skip until the first LF */ + i_stream_skip(input, 5); + while ( i_stream_read_more(input, &data, &size) > 0 ) { + for (i = 0; i < size; i++) { + if (data[i] == '\n') + break; + } + if (i != size) { + (void)mbox_from_parse(data, i, mtime_r, &tz, &env_sender); + i_stream_skip(input, i + 1); + break; + } + i_stream_skip(input, size); + } + } + + if (env_sender != NULL && sender != NULL) { + *sender = t_strdup(env_sender); + } + i_free(env_sender); + + if (input->v_offset == 0) { + input2 = input; + i_stream_ref(input2); + } else { + input2 = i_stream_create_limit(input, (uoff_t)-1); + } + i_stream_unref(&input); + + input_list[0] = input2; input_list[1] = NULL; + input = i_stream_create_seekable(input_list, MAIL_MAX_MEMORY_BUFFER, + seekable_fd_callback, (void*)ruser); + i_stream_unref(&input2); + return input; +} + +/* + * Init/Deinit + */ + +struct mail_user *mail_raw_user_create +(struct master_service *service, struct mail_user *mail_user) +{ + void **sets = master_service_settings_get_others(service); + + return raw_storage_create_from_set(mail_user->set_info, sets[0]); +} + +/* + * Open raw mail data + */ + +static struct mail_raw *mail_raw_create +(struct mail_user *ruser, struct istream *input, + const char *mailfile, const char *sender, time_t mtime) +{ + struct mail_raw *mailr; + struct mailbox_header_lookup_ctx *headers_ctx; + const char *envelope_sender, *error; + int ret; + + if ( mailfile != NULL && *mailfile != '/' ) + if (t_abspath(mailfile, &mailfile, &error) < 0) + i_fatal("t_abspath(%s) failed: %s", + mailfile, error); + + mailr = i_new(struct mail_raw, 1); + + envelope_sender = sender != NULL ? sender : DEFAULT_ENVELOPE_SENDER; + if ( mailfile == NULL ) { + ret = raw_mailbox_alloc_stream(ruser, input, mtime, + envelope_sender, &mailr->box); + } else { + ret = raw_mailbox_alloc_path(ruser, mailfile, (time_t)-1, + envelope_sender, &mailr->box); + } + + if ( ret < 0 ) { + if ( mailfile == NULL ) { + i_fatal("Can't open delivery mail as raw: %s", + mailbox_get_last_internal_error(mailr->box, NULL)); + } else { + i_fatal("Can't open delivery mail as raw (file=%s): %s", + mailfile, mailbox_get_last_internal_error(mailr->box, NULL)); + } + } + + mailr->trans = mailbox_transaction_begin(mailr->box, 0, __func__); + headers_ctx = mailbox_header_lookup_init(mailr->box, wanted_headers); + mailr->mail = mail_alloc(mailr->trans, 0, headers_ctx); + mailbox_header_lookup_unref(&headers_ctx); + mail_set_seq(mailr->mail, 1); + + return mailr; +} + +struct mail_raw *mail_raw_open_stream +(struct mail_user *ruser, struct istream *input) +{ + struct mail_raw *mailr; + + i_assert(input->seekable); + i_stream_set_name(input, "data"); + mailr = mail_raw_create(ruser, input, NULL, NULL, (time_t)-1); + + return mailr; +} + +struct mail_raw *mail_raw_open_data +(struct mail_user *ruser, string_t *mail_data) +{ + struct mail_raw *mailr; + struct istream *input; + + input = i_stream_create_from_data(str_data(mail_data), str_len(mail_data)); + + mailr = mail_raw_open_stream(ruser, input); + + i_stream_unref(&input); + return mailr; +} + +struct mail_raw *mail_raw_open_file +(struct mail_user *ruser, const char *path) +{ + struct mail_raw *mailr; + struct istream *input = NULL; + time_t mtime = (time_t)-1; + const char *sender = NULL; + + if ( path == NULL || strcmp(path, "-") == 0 ) { + path = NULL; + input = mail_raw_create_stream(ruser, 0, &mtime, &sender); + } + + mailr = mail_raw_create(ruser, input, path, sender, mtime); + i_stream_unref(&input); + + return mailr; +} + +void mail_raw_close(struct mail_raw **mailr) +{ + mail_free(&(*mailr)->mail); + mailbox_transaction_rollback(&(*mailr)->trans); + mailbox_free(&(*mailr)->box); + + i_free(*mailr); + *mailr = NULL; +} + |