1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
4
/* FIXME: This file was gratefully stolen from dovecot/src/deliver/deliver.c and
5
* altered to suit our needs. So, this contains lots and lots of duplicated
11
#include "istream-seekable.h"
12
#include "fd-set-nonblock.h"
14
#include "str-sanitize.h"
15
#include "strescape.h"
16
#include "safe-mkstemp.h"
17
#include "close-keep-errno.h"
18
#include "mkdir-parents.h"
19
#include "message-address.h"
20
#include "mbox-from.h"
21
#include "raw-storage.h"
22
#include "mail-namespace.h"
36
#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON"
38
/* After buffer grows larger than this, create a temporary file to /tmp
39
where to read the mail. */
40
#define MAIL_MAX_MEMORY_BUFFER (1024*128)
42
static const char *wanted_headers[] = {
43
"From", "Message-ID", "Subject", "Return-Path",
51
static struct mail_namespace *raw_ns;
52
static struct mail_user *raw_mail_user;
55
* Raw mail implementation
58
static int seekable_fd_callback
59
(const char **path_r, void *context ATTR_UNUSED)
65
path = t_str_new(128);
66
str_append(path, "/tmp/dovecot.sieve-tool.");
67
fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
68
if (fd == -1 && errno == ENOENT) {
70
p = strrchr(dir, '/');
72
dir = t_strdup_until(dir, p);
73
if ( mkdir_parents(dir, 0600) < 0 ) {
74
i_error("mkdir_parents(%s) failed: %m", dir);
77
fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
82
i_error("safe_mkstemp(%s) failed: %m", str_c(path));
86
/* we just want the fd, unlink it */
87
if (unlink(str_c(path)) < 0) {
88
/* shouldn't happen.. */
89
i_error("unlink(%s) failed: %m", str_c(path));
94
*path_r = str_c(path);
98
static struct istream *create_raw_stream
99
(int fd, time_t *mtime_r, const char **sender)
101
struct istream *input, *input2, *input_list[2];
102
const unsigned char *data;
107
*mtime_r = (time_t)-1;
108
fd_set_nonblock(fd, FALSE);
110
input = i_stream_create_fd(fd, 4096, FALSE);
111
input->blocking = TRUE;
112
/* If input begins with a From-line, drop it */
113
ret = i_stream_read_data(input, &data, &size, 5);
114
if (ret > 0 && size >= 5 && memcmp(data, "From ", 5) == 0) {
115
/* skip until the first LF */
116
i_stream_skip(input, 5);
117
while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
118
for (i = 0; i < size; i++) {
123
(void)mbox_from_parse(data, i, mtime_r, &tz, &env_sender);
124
i_stream_skip(input, i + 1);
127
i_stream_skip(input, size);
131
if (sender != NULL) {
132
*sender = t_strdup(env_sender);
136
if (input->v_offset == 0) {
138
i_stream_ref(input2);
140
input2 = i_stream_create_limit(input, (uoff_t)-1);
142
i_stream_unref(&input);
144
input_list[0] = input2; input_list[1] = NULL;
145
input = i_stream_create_seekable(input_list, MAIL_MAX_MEMORY_BUFFER,
146
seekable_fd_callback, raw_mail_user);
147
i_stream_unref(&input2);
156
void mail_raw_init(const char *user)
160
raw_mail_user = mail_user_init(user);
161
mail_user_set_home(raw_mail_user, NULL);
162
raw_ns = mail_namespaces_init_empty(raw_mail_user);
163
raw_ns->flags |= NAMESPACE_FLAG_NOQUOTA | NAMESPACE_FLAG_NOACL;
165
if ( mail_storage_create(raw_ns, "raw", "/tmp",
166
MAIL_STORAGE_FLAG_FULL_FS_ACCESS,
167
FILE_LOCK_METHOD_FCNTL, &error) < 0 ) {
168
i_fatal("Couldn't create internal raw storage: %s", error);
172
void mail_raw_deinit(void)
174
mail_user_unref(&raw_mail_user);
182
static struct mail_raw *mail_raw_create
183
(struct istream *input, const char *mailfile, const char *sender,
187
struct raw_mailbox *raw_box;
188
struct mail_raw *mailr;
189
enum mail_error error;
191
if ( mailfile != NULL ) {
192
if ( *mailfile != '/') {
195
/* Expand relative paths */
196
if (getcwd(cwd, sizeof(cwd)) == NULL)
197
i_fatal("getcwd() failed: %m");
199
mailfile = t_strconcat(cwd, "/", mailfile, NULL);
203
pool = pool_alloconly_create("mail_raw", 1024);
204
mailr = p_new(pool, struct mail_raw, 1);
207
if ( mailfile == NULL ) {
208
mailr->box = mailbox_open(&raw_ns->storage, "Dovecot Raw Mail",
209
input, MAILBOX_OPEN_NO_INDEX_FILES);
212
mailr->box = mailbox_open(&raw_ns->storage, mailfile, NULL,
213
MAILBOX_OPEN_NO_INDEX_FILES);
216
if ( mailr->box == NULL ) {
217
i_fatal("Can't open mail stream as raw: %s",
218
mail_storage_get_last_error(raw_ns->storage, &error));
221
if ( mailbox_sync(mailr->box, 0, 0, NULL ) < 0) {
222
enum mail_error error;
224
i_fatal("Can't sync delivery mail: %s",
225
mail_storage_get_last_error(raw_ns->storage, &error));
228
raw_box = (struct raw_mailbox *)mailr->box;
229
raw_box->envelope_sender = sender != NULL ? sender : DEFAULT_ENVELOPE_SENDER;
230
raw_box->mtime = mtime;
232
mailr->trans = mailbox_transaction_begin(mailr->box, 0);
233
mailr->headers_ctx = mailbox_header_lookup_init(mailr->box, wanted_headers);
234
mailr->mail = mail_alloc(mailr->trans, 0, mailr->headers_ctx);
235
mail_set_seq(mailr->mail, 1);
240
struct mail_raw *mail_raw_open_data(string_t *mail_data)
242
struct mail_raw *mailr;
243
struct istream *input;
245
input = i_stream_create_from_data(str_data(mail_data), str_len(mail_data));
247
mailr = mail_raw_create(input, NULL, NULL, (time_t)-1);
249
i_stream_unref(&input);
254
struct mail_raw *mail_raw_open_file(const char *path)
256
struct mail_raw *mailr;
257
struct istream *input = NULL;
259
const char *sender = NULL;
261
if ( path == NULL || strcmp(path, "-") == 0 ) {
263
input = create_raw_stream(0, &mtime, &sender);
266
mailr = mail_raw_create(input, path, sender, mtime);
269
i_stream_unref(&input);
274
void mail_raw_close(struct mail_raw *mailr)
276
mailbox_header_lookup_unref(&mailr->headers_ctx);
278
mail_free(&mailr->mail);
279
mailbox_transaction_rollback(&mailr->trans);
280
mailbox_close(&mailr->box);
282
pool_unref(&mailr->pool);