dovecot-2.0: lmtp: If delivering duplicate messages to same user...
dovecot at dovecot.org
dovecot at dovecot.org
Mon Jan 3 18:59:18 EET 2011
details: http://hg.dovecot.org/dovecot-2.0/rev/2b8d7b6bcfc7
changeset: 12538:2b8d7b6bcfc7
user: Timo Sirainen <tss at iki.fi>
date: Mon Jan 03 18:59:07 2011 +0200
description:
lmtp: If delivering duplicate messages to same user's INBOX, use different GUIDs.
This is to avoid POP3 clients getting confused with duplicate UIDLs, when
using GUIDs as UIDLs.
diffstat:
src/lda/main.c | 5 +-
src/lib-lda/mail-deliver.c | 57 ++++++++++++++++++++++++++++
src/lib-lda/mail-deliver.h | 15 +++++++
src/lmtp/commands.c | 16 +++++---
4 files changed, 85 insertions(+), 8 deletions(-)
diffs (219 lines):
diff -r 384d8615039f -r 2b8d7b6bcfc7 src/lda/main.c
--- a/src/lda/main.c Mon Jan 03 18:57:05 2011 +0200
+++ b/src/lda/main.c Mon Jan 03 18:59:07 2011 +0200
@@ -255,7 +255,8 @@
&argc, &argv, "a:d:ef:km:p:r:");
memset(&ctx, 0, sizeof(ctx));
- ctx.pool = pool_alloconly_create("mail deliver context", 256);
+ ctx.session = mail_deliver_session_init();
+ ctx.pool = ctx.session->pool;
ctx.dest_mailbox_name = "INBOX";
path = NULL;
@@ -467,7 +468,7 @@
mail_user_unref(&ctx.dest_user);
mail_user_unref(&raw_mail_user);
- pool_unref(&ctx.pool);
+ mail_deliver_session_deinit(&ctx.session);
mail_storage_service_user_free(&service_user);
mail_storage_service_deinit(&storage_service);
diff -r 384d8615039f -r 2b8d7b6bcfc7 src/lib-lda/mail-deliver.c
--- a/src/lib-lda/mail-deliver.c Mon Jan 03 18:57:05 2011 +0200
+++ b/src/lib-lda/mail-deliver.c Mon Jan 03 18:59:07 2011 +0200
@@ -116,6 +116,25 @@
va_end(args);
}
+struct mail_deliver_session *mail_deliver_session_init(void)
+{
+ struct mail_deliver_session *session;
+ pool_t pool;
+
+ pool = pool_alloconly_create("mail deliver session", 1024);
+ session = p_new(pool, struct mail_deliver_session, 1);
+ session->pool = pool;
+ return session;
+}
+
+void mail_deliver_session_deinit(struct mail_deliver_session **_session)
+{
+ struct mail_deliver_session *session = *_session;
+
+ *_session = NULL;
+ pool_unref(&session->pool);
+}
+
static const char *mailbox_name_to_mutf7(const char *mailbox_utf8)
{
string_t *str = t_str_new(128);
@@ -191,6 +210,43 @@
return 0;
}
+static bool mail_deliver_check_duplicate(struct mail_deliver_session *session,
+ struct mail_user *user)
+{
+ const char *const *usernamep, *username;
+
+ /* there shouldn't be all that many recipients,
+ so just do a linear search */
+ if (!array_is_created(&session->inbox_users))
+ p_array_init(&session->inbox_users, session->pool, 8);
+ array_foreach(&session->inbox_users, usernamep) {
+ if (strcmp(*usernamep, user->username) == 0)
+ return TRUE;
+ }
+ username = p_strdup(session->pool, user->username);
+ array_append(&session->inbox_users, &username, 1);
+ return FALSE;
+}
+
+void mail_deliver_deduplicate_guid_if_needed(struct mail_deliver_context *ctx,
+ struct mail_save_context *save_ctx,
+ const char *mailbox)
+{
+ uint8_t guid[MAIL_GUID_128_SIZE];
+
+ if (strcasecmp(mailbox, "INBOX") != 0)
+ return;
+
+ /* avoid storing duplicate GUIDs to delivered mails to INBOX. this
+ happens if mail is delivered to same user multiple times within a
+ session. the problem with this is that if GUIDs are used as POP3
+ UIDLs, some clients can't handle the duplicates well. */
+ if (mail_deliver_check_duplicate(ctx->session, ctx->dest_user)) {
+ mail_generate_guid_128(guid);
+ mailbox_save_set_guid(save_ctx, mail_guid_128_to_string(guid));
+ }
+}
+
int mail_deliver_save(struct mail_deliver_context *ctx, const char *mailbox,
enum mail_flags flags, const char *const *keywords,
struct mail_storage **storage_r)
@@ -247,6 +303,7 @@
ctx->dest_mail = mail_alloc(t, lda_log_wanted_fetch_fields, NULL);
mailbox_header_lookup_unref(&headers_ctx);
mailbox_save_set_dest_mail(save_ctx, ctx->dest_mail);
+ mail_deliver_deduplicate_guid_if_needed(ctx, save_ctx, mailbox);
if (mailbox_copy(&save_ctx, ctx->src_mail) < 0)
ret = -1;
diff -r 384d8615039f -r 2b8d7b6bcfc7 src/lib-lda/mail-deliver.h
--- a/src/lib-lda/mail-deliver.h Mon Jan 03 18:57:05 2011 +0200
+++ b/src/lib-lda/mail-deliver.h Mon Jan 03 18:59:07 2011 +0200
@@ -4,11 +4,20 @@
enum mail_flags;
enum mail_error;
struct mail_storage;
+struct mail_save_context;
struct mailbox;
+struct mail_deliver_session {
+ pool_t pool;
+
+ /* List of users who have already saved this mail to their INBOX */
+ ARRAY_TYPE(const_string) inbox_users;
+};
+
struct mail_deliver_context {
pool_t pool;
const struct lda_settings *set;
+ struct mail_deliver_session *session;
struct duplicate_context *dup_ctx;
@@ -62,6 +71,9 @@
const char *mail_deliver_get_return_address(struct mail_deliver_context *ctx);
const char *mail_deliver_get_new_message_id(struct mail_deliver_context *ctx);
+struct mail_deliver_session *mail_deliver_session_init(void);
+void mail_deliver_session_deinit(struct mail_deliver_session **session);
+
/* Try to open mailbox for saving. Returns 0 if ok, -1 if error. The box may
be returned even with -1, and the caller must free it then. */
int mail_deliver_save_open(struct mail_deliver_save_open_context *ctx,
@@ -70,6 +82,9 @@
int mail_deliver_save(struct mail_deliver_context *ctx, const char *mailbox,
enum mail_flags flags, const char *const *keywords,
struct mail_storage **storage_r);
+void mail_deliver_deduplicate_guid_if_needed(struct mail_deliver_context *ctx,
+ struct mail_save_context *save_ctx,
+ const char *mailbox);
int mail_deliver(struct mail_deliver_context *ctx,
struct mail_storage **storage_r);
diff -r 384d8615039f -r 2b8d7b6bcfc7 src/lmtp/commands.c
--- a/src/lmtp/commands.c Mon Jan 03 18:57:05 2011 +0200
+++ b/src/lmtp/commands.c Mon Jan 03 18:59:07 2011 +0200
@@ -446,7 +446,7 @@
static int
client_deliver(struct client *client, const struct mail_recipient *rcpt,
- struct mail *src_mail)
+ struct mail *src_mail, struct mail_deliver_session *session)
{
struct mail_deliver_context dctx;
struct mail_storage *storage;
@@ -470,7 +470,8 @@
sets = mail_storage_service_user_get_set(rcpt->service_user);
memset(&dctx, 0, sizeof(dctx));
- dctx.pool = pool_alloconly_create("mail delivery", 1024);
+ dctx.session = session;
+ dctx.pool = session->pool;
dctx.set = sets[1];
dctx.session_id = client->state.session_id;
dctx.src_mail = src_mail;
@@ -516,11 +517,11 @@
}
ret = -1;
}
- pool_unref(&dctx.pool);
return ret;
}
-static bool client_deliver_next(struct client *client, struct mail *src_mail)
+static bool client_deliver_next(struct client *client, struct mail *src_mail,
+ struct mail_deliver_session *session)
{
const struct mail_recipient *rcpts;
unsigned int count;
@@ -529,7 +530,7 @@
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);
+ src_mail, session);
i_set_failure_prefix(t_strdup_printf("lmtp(%s): ", my_pid));
client->state.rcpt_idx++;
@@ -618,15 +619,17 @@
static void
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;
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)) {
+ 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);
@@ -639,6 +642,7 @@
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;
More information about the dovecot-cvs
mailing list