changeset 9133:a80db92d296b HEAD

lmtp: If mail is >128 kB, write it to a temporary file.
author Timo Sirainen <tss@iki.fi>
date Fri, 17 Apr 2009 12:54:49 -0400
parents dad05c75bd48
children 761fc36e0e34
files src/lmtp/commands.c
diffstat 1 files changed, 68 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/lmtp/commands.c	Fri Apr 17 12:54:10 2009 -0400
+++ b/src/lmtp/commands.c	Fri Apr 17 12:54:49 2009 -0400
@@ -3,7 +3,10 @@
 #include "lib.h"
 #include "ioloop.h"
 #include "array.h"
+#include "str.h"
 #include "istream.h"
+#include "ostream.h"
+#include "safe-mkstemp.h"
 #include "mail-storage-service.h"
 #include "index/raw/raw-storage.h"
 #include "lda-settings.h"
@@ -256,8 +259,14 @@
 	struct istream *input;
 	enum mail_error error;
 
-	input = i_stream_create_from_data(client->state.mail_data->data,
-					  client->state.mail_data->used);
+	if (client->state.mail_data_output != NULL) {
+		o_stream_unref(&client->state.mail_data_output);
+		input = i_stream_create_fd(client->state.mail_data_fd,
+					   MAIL_READ_BLOCK_SIZE, FALSE);
+	} else {
+		input = i_stream_create_from_data(client->state.mail_data->data,
+						  client->state.mail_data->used);
+	}
 	client->state.raw_box = box =
 		mailbox_open(&raw_storage, "Dovecot Delivery Mail", input,
 			     MAILBOX_OPEN_NO_INDEX_FILES);
@@ -325,10 +334,55 @@
 	}
 }
 
-static void
+static int client_input_add_file(struct client *client,
+				 const unsigned char *data, size_t size)
+{
+	string_t *path;
+	int fd;
+
+	if (client->state.mail_data_output != NULL) {
+		/* continue writing to file */
+		if (o_stream_send(client->state.mail_data_output,
+				  data, size) != (ssize_t)size)
+			return -1;
+		return 0;
+	}
+
+	/* move everything to a temporary file. FIXME: it really shouldn't
+	   be in /tmp.. */
+	path = t_str_new(256);
+	str_append(path, "/tmp/dovecot.lmtp.");
+	fd = safe_mkstemp_hostpid(path, 0600, (uid_t)-1, (gid_t)-1);
+	if (fd == -1)
+		return -1;
+
+	/* we just want the fd, unlink it */
+	if (unlink(str_c(path)) < 0) {
+		/* shouldn't happen.. */
+		i_error("unlink(%s) failed: %m", str_c(path));
+		(void)close(fd);
+		return -1;
+	}
+
+	client->state.mail_data_fd = fd;
+	client->state.mail_data_output = o_stream_create_fd_file(fd, 0, FALSE);
+	o_stream_cork(client->state.mail_data_output);
+	if (o_stream_send(client->state.mail_data_output,
+			  data, size) != (ssize_t)size)
+		return -1;
+	return 0;
+}
+
+static int
 client_input_add(struct client *client, const unsigned char *data, size_t size)
 {
-	buffer_append(client->state.mail_data, data, size);
+	if (client->state.mail_data->used + size <=
+	    CLIENT_MAIL_DATA_MAX_INMEMORY_SIZE) {
+		buffer_append(client->state.mail_data, data, size);
+		return 0;
+	} else {
+		return client_input_add_file(client, data, size);
+	}
 }
 
 static void client_input_data_handle(struct client *client)
@@ -353,7 +407,11 @@
 			}
 		} else if (client->state.data_end_idx == DATA_DOT_NEXT_POS) {
 			/* saw a dot at the beginning of line. drop it. */
-			client_input_add(client, data, i-1);
+			if (client_input_add(client, data, i-1) < 0) {
+				client_destroy(client, "451 4.3.0",
+					       "Temporary internal failure");
+				return;
+			}
 			start = i;
 			client->state.data_end_idx = 0;
 		} else {
@@ -366,7 +424,11 @@
 		rewind = client->state.data_end_idx - DATA_DOT_NEXT_POS + 1;
 		i -= rewind; size -= rewind;
 	}
-	client_input_add(client, data + start, i-start);
+	if (client_input_add(client, data + start, i-start) < 0) {
+		client_destroy(client, "451 4.3.0",
+			       "Temporary internal failure");
+		return;
+	}
 	i_stream_skip(client->input, skip == 0 ? i : skip);
 
 	if (i < size) {