dovecot-2.2: lmtp: Put back the deduplication code.
dovecot at dovecot.org
dovecot at dovecot.org
Wed Aug 20 13:32:37 UTC 2014
details: http://hg.dovecot.org/dovecot-2.2/rev/f0f19e5580f0
changeset: 17736:f0f19e5580f0
user: Timo Sirainen <tss at iki.fi>
date: Wed Aug 20 15:32:15 2014 +0200
description:
lmtp: Put back the deduplication code.
Too dangerous after all to change it in the middle of v2.2.x. It's also not
causing that much trouble even when it breaks..
diffstat:
src/lmtp/client.h | 4 ++
src/lmtp/commands.c | 82 ++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 70 insertions(+), 16 deletions(-)
diffs (185 lines):
diff -r c3da5ffaa0f2 -r f0f19e5580f0 src/lmtp/client.h
--- a/src/lmtp/client.h Wed Aug 20 14:35:27 2014 +0200
+++ b/src/lmtp/client.h Wed Aug 20 15:32:15 2014 +0200
@@ -16,6 +16,7 @@
const char *session_id;
const char *mail_from;
ARRAY(struct mail_recipient) rcpt_to;
+ unsigned int rcpt_idx;
unsigned int data_end_idx;
@@ -28,6 +29,9 @@
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;
};
diff -r c3da5ffaa0f2 -r f0f19e5580f0 src/lmtp/commands.c
--- a/src/lmtp/commands.c Wed Aug 20 14:35:27 2014 +0200
+++ b/src/lmtp/commands.c Wed Aug 20 15:32:15 2014 +0200
@@ -614,7 +614,7 @@
static int
client_deliver(struct client *client, const struct mail_recipient *rcpt,
- struct mail_deliver_session *session)
+ struct mail *src_mail, struct mail_deliver_session *session)
{
struct mail_deliver_context dctx;
struct mail_storage *storage;
@@ -622,7 +622,6 @@
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;
@@ -650,7 +649,7 @@
i_set_failure_prefix("lmtp(%s, %s): ", my_pid, username);
if (mail_storage_service_next(storage_service, rcpt->service_user,
- &dest_user) < 0) {
+ &client->state.dest_user) < 0) {
client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
rcpt->address);
return -1;
@@ -658,18 +657,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(dest_user));
+ mail_user_var_expand_table(client->state.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 = client->state.raw_mail;
+ dctx.src_mail = src_mail;
dctx.src_envelope_sender = client->state.mail_from;
- dctx.dest_user = dest_user;
+ dctx.dest_user = client->state.dest_user;
if (*dctx.set->lda_original_recipient_header != '\0') {
- dctx.dest_addr = mail_deliver_get_address(dctx.src_mail,
+ dctx.dest_addr = mail_deliver_get_address(src_mail,
dctx.set->lda_original_recipient_header);
}
if (dctx.dest_addr == NULL)
@@ -679,12 +678,19 @@
!client->lmtp_set->lmtp_save_to_detail_mailbox)
dctx.dest_mailbox_name = "INBOX";
else {
- ns = mail_namespace_find_inbox(dest_user->namespaces);
+ ns = mail_namespace_find_inbox(dctx.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;
@@ -711,21 +717,30 @@
rcpt->address);
ret = -1;
}
- mail_user_unref(&dest_user);
return ret;
}
-static void client_deliver_mails(struct client *client,
- struct mail_deliver_session *session)
+static bool client_deliver_next(struct client *client, struct mail *src_mail,
+ struct mail_deliver_session *session)
{
const struct mail_recipient *rcpts;
- unsigned int i, count;
+ unsigned int count;
+ int ret;
rcpts = array_get(&client->state.rcpt_to, &count);
- for (i = 0; i < count; i++) {
- (void)client_deliver(client, &rcpts[i], session);
+ while (client->state.rcpt_idx < count) {
+ ret = client_deliver(client, &rcpts[client->state.rcpt_idx],
+ src_mail, 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;
}
static void client_rcpt_fail_all(struct client *client)
@@ -800,16 +815,51 @@
client_input_data_write_local(struct client *client, struct istream *input)
{
struct mail_deliver_session *session;
- uid_t old_uid;
+ struct mail *src_mail;
+ uid_t old_uid, first_uid = (uid_t)-1;
if (client_open_raw_mail(client, input) < 0)
return;
session = mail_deliver_session_init();
old_uid = geteuid();
- client_deliver_mails(client, session);
+ 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);
+ }
+ }
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
More information about the dovecot-cvs
mailing list