changeset 17588:51274bf2a47d

lmtp: Removed code that attempts to deduplicate mail files by copying them between user mailboxes. This sometimes started failing if the mail that was being used for copying was deleted by the user. There's no good way for lmtp code to fix that situation. If deduplication is needed, it could be implemented in a more generic way inside mailbox_copy() where after initial copy it would store the destination struct mail to src_mail->last_copy_dest_mail. If another mail is copied, the last_copy_dest_mail could be attempted to be used for the copying and if that doesn't work it would fallback to regular copying. This should probably be attempted only for lda/lmtp processes as it would just cause extra overhead for others.
author Timo Sirainen <tss@iki.fi>
date Thu, 03 Jul 2014 20:28:16 +0300
parents 4c4db2d76137
children 5f21c78cd7b2
files src/lmtp/client.h src/lmtp/commands.c
diffstat 2 files changed, 14 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/src/lmtp/client.h	Thu Jul 03 19:34:57 2014 +0300
+++ b/src/lmtp/client.h	Thu Jul 03 20:28:16 2014 +0300
@@ -29,9 +29,6 @@
 
 	struct mail *raw_mail;
 
-	struct mail_user *dest_user;
-	struct mail *first_saved_mail;
-
 	unsigned int mail_body_7bit:1;
 	unsigned int mail_body_8bitmime:1;
 };
--- a/src/lmtp/commands.c	Thu Jul 03 19:34:57 2014 +0300
+++ b/src/lmtp/commands.c	Thu Jul 03 20:28:16 2014 +0300
@@ -614,7 +614,7 @@
 
 static int
 client_deliver(struct client *client, const struct mail_recipient *rcpt,
-	       struct mail *src_mail, struct mail_deliver_session *session)
+	       struct mail_deliver_session *session)
 {
 	struct mail_deliver_context dctx;
 	struct mail_storage *storage;
@@ -622,6 +622,7 @@
 	const struct mail_storage_settings *mail_set;
 	struct lda_settings *lda_set;
 	struct mail_namespace *ns;
+	struct mail_user *dest_user;
 	struct setting_parser_context *set_parser;
 	void **sets;
 	const char *line, *error, *username;
@@ -649,7 +650,7 @@
 
 	i_set_failure_prefix("lmtp(%s, %s): ", my_pid, username);
 	if (mail_storage_service_next(storage_service, rcpt->service_user,
-				      &client->state.dest_user) < 0) {
+				      &dest_user) < 0) {
 		client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
 				 rcpt->address);
 		return -1;
@@ -657,18 +658,18 @@
 	sets = mail_storage_service_user_get_set(rcpt->service_user);
 	lda_set = sets[1];
 	settings_var_expand(&lda_setting_parser_info, lda_set, client->pool,
-		mail_user_var_expand_table(client->state.dest_user));
+		mail_user_var_expand_table(dest_user));
 
 	memset(&dctx, 0, sizeof(dctx));
 	dctx.session = session;
 	dctx.pool = session->pool;
 	dctx.set = lda_set;
 	dctx.session_id = client->state.session_id;
-	dctx.src_mail = src_mail;
+	dctx.src_mail = client->state.raw_mail;
 	dctx.src_envelope_sender = client->state.mail_from;
-	dctx.dest_user = client->state.dest_user;
+	dctx.dest_user = dest_user;
 	if (*dctx.set->lda_original_recipient_header != '\0') {
-		dctx.dest_addr = mail_deliver_get_address(src_mail,
+		dctx.dest_addr = mail_deliver_get_address(dctx.src_mail,
 				dctx.set->lda_original_recipient_header);
 	}
 	if (dctx.dest_addr == NULL)
@@ -678,19 +679,12 @@
 	    !client->lmtp_set->lmtp_save_to_detail_mailbox)
 		dctx.dest_mailbox_name = "INBOX";
 	else {
-		ns = mail_namespace_find_inbox(dctx.dest_user->namespaces);
+		ns = mail_namespace_find_inbox(dest_user->namespaces);
 		dctx.dest_mailbox_name =
 			t_strconcat(ns->prefix, rcpt->detail, NULL);
 	}
 
-	dctx.save_dest_mail = array_count(&client->state.rcpt_to) > 1 &&
-		client->state.first_saved_mail == NULL;
-
 	if (mail_deliver(&dctx, &storage) == 0) {
-		if (dctx.dest_mail != NULL) {
-			i_assert(client->state.first_saved_mail == NULL);
-			client->state.first_saved_mail = dctx.dest_mail;
-		}
 		client_send_line(client, "250 2.0.0 <%s> %s Saved",
 				 rcpt->address, client->state.session_id);
 		ret = 0;
@@ -717,10 +711,11 @@
 				 rcpt->address);
 		ret = -1;
 	}
+	mail_user_unref(&dest_user);
 	return ret;
 }
 
-static bool client_deliver_next(struct client *client, struct mail *src_mail,
+static bool client_deliver_next(struct client *client,
 				struct mail_deliver_session *session)
 {
 	const struct mail_recipient *rcpts;
@@ -730,15 +725,13 @@
 	rcpts = array_get(&client->state.rcpt_to, &count);
 	while (client->state.rcpt_idx < count) {
 		ret = client_deliver(client, &rcpts[client->state.rcpt_idx],
-				     src_mail, session);
+				     session);
 		i_set_failure_prefix("lmtp(%s): ", my_pid);
 
 		client->state.rcpt_idx++;
 		if (ret == 0)
 			return TRUE;
 		/* failed. try the next one. */
-		if (client->state.dest_user != NULL)
-			mail_user_unref(&client->state.dest_user);
 	}
 	return FALSE;
 }
@@ -815,51 +808,17 @@
 client_input_data_write_local(struct client *client, struct istream *input)
 {
 	struct mail_deliver_session *session;
-	struct mail *src_mail;
-	uid_t old_uid, first_uid = (uid_t)-1;
+	uid_t old_uid;
 
 	if (client_open_raw_mail(client, input) < 0)
 		return;
 
 	session = mail_deliver_session_init();
 	old_uid = geteuid();
-	src_mail = client->state.raw_mail;
-	while (client_deliver_next(client, src_mail, session)) {
-		if (client->state.first_saved_mail == NULL ||
-		    client->state.first_saved_mail == src_mail)
-			mail_user_unref(&client->state.dest_user);
-		else {
-			/* use the first saved message to save it elsewhere too.
-			   this might allow hard linking the files. */
-			client->state.dest_user = NULL;
-			src_mail = client->state.first_saved_mail;
-			first_uid = geteuid();
-			i_assert(first_uid != 0);
-		}
-	}
+	while (client_deliver_next(client, session))
+		;
 	mail_deliver_session_deinit(&session);
 
-	if (client->state.first_saved_mail != NULL) {
-		struct mail *mail = client->state.first_saved_mail;
-		struct mailbox_transaction_context *trans = mail->transaction;
-		struct mailbox *box = trans->box;
-		struct mail_user *user = box->storage->user;
-
-		/* just in case these functions are going to write anything,
-		   change uid back to user's own one */
-		if (first_uid != old_uid) {
-			if (seteuid(0) < 0)
-				i_fatal("seteuid(0) failed: %m");
-			if (seteuid(first_uid) < 0)
-				i_fatal("seteuid() failed: %m");
-		}
-
-		mail_free(&mail);
-		mailbox_transaction_rollback(&trans);
-		mailbox_free(&box);
-		mail_user_unref(&user);
-	}
-
 	if (old_uid == 0) {
 		/* switch back to running as root, since that's what we're
 		   practically doing anyway. it's also important in case we