]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lmtp: Split off local delivery in a struct separate from the client.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sun, 22 Oct 2017 21:29:21 +0000 (23:29 +0200)
committerStephan Bosch <stephan.bosch@dovecot.fi>
Thu, 7 Dec 2017 23:08:16 +0000 (00:08 +0100)
This mimics proxy delivery, making the implementation better structured.

src/lmtp/client.c
src/lmtp/client.h
src/lmtp/commands.c
src/lmtp/lmtp-local.c
src/lmtp/lmtp-local.h
src/lmtp/lmtp-proxy.c
src/lmtp/lmtp-proxy.h

index 96926bf16b593f7c65be93caf8ce0a55f98bde6d..200b1cba0b1b2d4cc64bb71da165448e10b7a0ee 100644 (file)
@@ -125,6 +125,11 @@ static void client_read_settings(struct client *client)
        client->unexpanded_lda_set = lda_set;
 }
 
+unsigned int client_get_rcpt_count(struct client *client)
+{
+       return lmtp_local_rcpt_count(client) + lmtp_proxy_rcpt_count(client);
+}
+
 static void client_generate_session_id(struct client *client)
 {
        guid_128_t guid;
@@ -186,27 +191,11 @@ struct client *client_create(int fd_in, int fd_out,
 
 void client_state_reset(struct client *client, const char *state_name)
 {
-       struct lmtp_recipient *const *rcptp;
-
+       if (client->local != NULL)
+               lmtp_local_deinit(&client->local);
        if (client->proxy != NULL)
                lmtp_proxy_deinit(&client->proxy);
 
-       if (array_is_created(&client->state.rcpt_to)) {
-               array_foreach_modifiable(&client->state.rcpt_to, rcptp) {
-                       lmtp_local_rcpt_deinit(*rcptp);
-               }
-       }
-
-       if (client->state.raw_mail != NULL) {
-               struct mailbox_transaction_context *raw_trans =
-                       client->state.raw_mail->transaction;
-               struct mailbox *raw_box = client->state.raw_mail->box;
-
-               mail_free(&client->state.raw_mail);
-               mailbox_transaction_rollback(&raw_trans);
-               mailbox_free(&raw_box);
-       }
-
        buffer_free(&client->state.mail_data);
        o_stream_unref(&client->state.mail_data_output);
        i_close_fd(&client->state.mail_data_fd);
@@ -232,6 +221,8 @@ void client_destroy(struct client *client, const char *prefix,
 
        if (client->raw_mail_user != NULL)
                mail_user_unref(&client->raw_mail_user);
+       if (client->local != NULL)
+               lmtp_local_deinit(&client->local);
        if (client->proxy != NULL)
                lmtp_proxy_deinit(&client->proxy);
        io_remove(&client->io);
index 1c120f7b322789953fbdad2059d8275999be84f4..57edf3c4df319a751a9eecd7c397a0a38ba22d7a 100644 (file)
@@ -13,10 +13,6 @@ struct lmtp_recipient {
        struct smtp_address *address;
        const char *detail; /* +detail part is also in address */
        struct smtp_params_rcpt params;
-
-       struct anvil_query *anvil_query;
-       bool anvil_connect_sent;
-       struct mail_storage_service_user *service_user;
 };
 
 struct client_state {
@@ -24,7 +20,6 @@ struct client_state {
        const char *session_id;
        struct smtp_address *mail_from;
        struct smtp_params_mail mail_params;
-       ARRAY(struct lmtp_recipient *) rcpt_to;
 
        unsigned int data_end_idx;
 
@@ -36,11 +31,6 @@ struct client_state {
        const char *added_headers;
 
        struct timeval mail_from_timeval, data_end_timeval;
-
-       struct mail *raw_mail;
-
-       struct mail_user *dest_user;
-       struct mail *first_saved_mail;
 };
 
 struct client {
@@ -70,6 +60,7 @@ struct client {
        pool_t state_pool;
        struct client_state state;
        struct istream *dot_input;
+       struct lmtp_local *local;
        struct lmtp_proxy *proxy;
        unsigned int proxy_ttl;
        unsigned int proxy_timeout_secs;
@@ -85,6 +76,7 @@ void client_destroy(struct client *client, const char *prefix,
                    const char *reason) ATTR_NULL(2, 3);
 void client_disconnect(struct client *client, const char *prefix,
                       const char *reason);
+unsigned int client_get_rcpt_count(struct client *client);
 void client_state_reset(struct client *client, const char *state_name);
 void client_state_set(struct client *client, const char *name, const char *args);
 const char *client_remote_id(struct client *client);
index 0f8eea1527b130ebe47fae0b9b6574d6b20483c1..361f1ce78830e0b10ed48e1b592bd6c92f7e9a7e 100644 (file)
@@ -164,7 +164,6 @@ int cmd_mail(struct client *client, const char *args)
 
        client->state.mail_from =
                smtp_address_clone(client->state_pool, address);
-       p_array_init(&client->state.rcpt_to, client->state_pool, 64);
        client_send_line(client, "250 2.1.0 OK");
        client_state_set(client, "MAIL FROM",
                smtp_address_encode(address));
@@ -184,9 +183,9 @@ int cmd_mail(struct client *client, const char *args)
 
 int cmd_rcpt(struct client *client, const char *args)
 {
-       struct lmtp_recipient *rcpt;
        struct smtp_address *address;
        const char *username, *detail;
+       struct smtp_params_rcpt params;
        enum smtp_param_parse_error pperror;
        const char *error = NULL;
        char delim = '\0';
@@ -214,13 +213,10 @@ int cmd_rcpt(struct client *client, const char *args)
                return 0;
        }
 
-       rcpt = p_new(client->state_pool, struct lmtp_recipient, 1);
-       rcpt->client = client;
-
        /* [SP Rcpt-parameters] */
        if (smtp_params_rcpt_parse(client->state_pool, args,
                SMTP_CAPABILITY_DSN, FALSE,
-               &rcpt->params, &pperror, &error) < 0) {
+               &params, &pperror, &error) < 0) {
                switch (pperror) {
                case SMTP_PARAM_PARSE_ERROR_BAD_SYNTAX:
                        client_send_line(client, "501 5.5.4 %s", error);
@@ -243,11 +239,12 @@ int cmd_rcpt(struct client *client, const char *args)
 
        if (client->lmtp_set->lmtp_proxy) {
                if (lmtp_proxy_rcpt(client, address, username, detail, delim,
-                                     &rcpt->params) != 0)
+                                     &params) != 0)
                        return 0;
        }
 
-       return lmtp_local_rcpt(client, rcpt, address, username, detail);
+       return lmtp_local_rcpt(client, address, username, detail,
+                              &params);
 }
 
 /*
@@ -345,41 +342,11 @@ static void client_proxy_finish(void *context)
 static const char *client_get_added_headers(struct client *client)
 {
        string_t *str = t_str_new(200);
-       void **sets;
-       const struct lmtp_settings *lmtp_set;
-       const struct smtp_address *rcpt_to = NULL;
-       const char *host;
-
-       if (array_count(&client->state.rcpt_to) == 1) {
-               struct lmtp_recipient *const *rcptp =
-                       array_idx(&client->state.rcpt_to, 0);
-
-               sets = mail_storage_service_user_get_set((*rcptp)->service_user);
-               lmtp_set = sets[3];
+       const char *host, *rcpt_to = NULL;
 
-               switch (lmtp_set->parsed_lmtp_hdr_delivery_address) {
-               case LMTP_HDR_DELIVERY_ADDRESS_NONE:
-                       break;
-               case LMTP_HDR_DELIVERY_ADDRESS_FINAL:
-                       rcpt_to = (*rcptp)->address;
-                       break;
-               case LMTP_HDR_DELIVERY_ADDRESS_ORIGINAL:
-                       rcpt_to = (*rcptp)->params.orcpt.addr;
-                       if (rcpt_to == NULL)
-                               rcpt_to = (*rcptp)->address;
-                       break;
-               }
-       }
-
-       /* don't set Return-Path when proxying so it won't get added twice */
-       if (array_count(&client->state.rcpt_to) > 0) {
-               str_printfa(str, "Return-Path: <%s>\r\n",
-                           smtp_address_encode(client->state.mail_from));
-               if (rcpt_to != NULL) {
-                       str_printfa(str, "Delivered-To: %s\r\n",
-                               smtp_address_encode(rcpt_to));
-               }
-       }
+       /* headers for local deliveries only */
+       if (client->local != NULL)
+               lmtp_local_add_headers(client->local, str);
 
        str_printfa(str, "Received: from %s", client->lhlo);
        host = net_ip2addr(&client->remote_ip);
@@ -395,7 +362,7 @@ static const char *client_get_added_headers(struct client *client)
 
        str_append(str, "\r\n\t");
        if (rcpt_to != NULL)
-               str_printfa(str, "for <%s>", smtp_address_encode(rcpt_to));
+               str_printfa(str, "for <%s>", rcpt_to);
        str_printfa(str, "; %s\r\n", message_date_create(ioloop_time));
        return str_c(str);
 }
@@ -412,7 +379,7 @@ static void client_input_data_write(struct client *client)
        client->state.data_end_timeval = ioloop_timeval;
 
        input = client_get_input(client);
-       if (array_count(&client->state.rcpt_to) != 0)
+       if (lmtp_local_rcpt_count(client) != 0)
                lmtp_local_data(client, input);
        if (client->proxy != NULL) {
                client_state_set(client, "DATA", "proxying");
@@ -526,7 +493,8 @@ int cmd_data(struct client *client, const char *args ATTR_UNUSED)
                client_send_line(client, "503 5.5.1 MAIL needed first");
                return 0;
        }
-       if (array_count(&client->state.rcpt_to) == 0 && client->proxy == NULL) {
+       if ((lmtp_local_rcpt_count(client) +
+            lmtp_proxy_rcpt_count(client)) == 0) {
                client_send_line(client, "554 5.5.1 No valid recipients");
                return 0;
        }
index a4df61ccf2a1bab95a1fa67152e6d09d1fec9845..a1c18feae2ada1a3cb3da7ed99a4a33f2e6f4ec8 100644 (file)
 #define ERRSTR_TEMP_MAILBOX_FAIL "451 4.3.0 <%s> Temporary internal error"
 #define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> "
 
+struct lmtp_local_recipient {
+       struct lmtp_recipient rcpt;
+       const char *session_id;
+
+       const char *detail;
+
+       struct mail_storage_service_user *service_user;
+       struct anvil_query *anvil_query;
+
+       bool anvil_connect_sent:1;
+};
+
+struct lmtp_local {
+       struct client *client;
+
+       ARRAY(struct lmtp_local_recipient *) rcpt_to;
+
+       struct mail *raw_mail, *first_saved_mail;
+       struct mail_user *rcpt_user;
+};
+
+static void
+lmtp_local_rcpt_deinit(struct lmtp_local_recipient *rcpt);
+
 /*
  * LMTP local
  */
 
+static struct lmtp_local *
+lmtp_local_init(struct client *client)
+{
+       struct lmtp_local *local;
+
+       local = i_new(struct lmtp_local, 1);
+       local->client = client;
+       i_array_init(&local->rcpt_to, 8);
+
+       return local;
+}
+
+void lmtp_local_deinit(struct lmtp_local **_local)
+{
+       struct lmtp_local *local = *_local;
+       struct lmtp_local_recipient *const *rcptp;
+
+       *_local = NULL;
+
+       if (array_is_created(&local->rcpt_to)) {
+               array_foreach_modifiable(&local->rcpt_to, rcptp)
+                       lmtp_local_rcpt_deinit(*rcptp);
+               array_free(&local->rcpt_to);
+       }
+
+       if (local->raw_mail != NULL) {
+               struct mailbox_transaction_context *raw_trans =
+                       local->raw_mail->transaction;
+               struct mailbox *raw_box = local->raw_mail->box;
+
+               mail_free(&local->raw_mail);
+               mailbox_transaction_rollback(&raw_trans);
+               mailbox_free(&raw_box);
+       }
+
+       i_free(local);
+}
+
 /*
  * Recipient
  */
 
+unsigned int lmtp_local_rcpt_count(struct client *client)
+{
+       if (client->local == NULL)
+               return 0;
+       return array_count(&client->local->rcpt_to);
+}
+
 static void
-lmtp_local_rcpt_anvil_disconnect(const struct lmtp_recipient *rcpt)
+lmtp_local_rcpt_anvil_disconnect(struct lmtp_local_recipient *rcpt)
 {
        const struct mail_storage_service_input *input;
 
@@ -51,7 +120,7 @@ lmtp_local_rcpt_anvil_disconnect(const struct lmtp_recipient *rcpt)
                "/", input->username, "\n", NULL));
 }
 
-void lmtp_local_rcpt_deinit(struct lmtp_recipient *rcpt)
+void lmtp_local_rcpt_deinit(struct lmtp_local_recipient *rcpt)
 {
        if (rcpt->anvil_query != NULL)
                anvil_client_query_abort(anvil, &rcpt->anvil_query);
@@ -60,25 +129,26 @@ void lmtp_local_rcpt_deinit(struct lmtp_recipient *rcpt)
 }
 
 static void
-client_send_line_overquota(struct client *client,
-                          const struct lmtp_recipient *rcpt, const char *error)
+lmtp_local_rcpt_reply_overquota(struct lmtp_local_recipient *rcpt,
+                               const char *error)
 {
+       struct client *client = rcpt->rcpt.client;
        struct lda_settings *lda_set =
                mail_storage_service_user_get_set(rcpt->service_user)[2];
 
        client_send_line(client, "%s <%s> %s",
                lda_set->quota_full_tempfail ? "452 4.2.2" : "552 5.2.2",
-               smtp_address_encode(rcpt->address), error);
+               smtp_address_encode(rcpt->rcpt.address), error);
 }
 
 static void
-client_rcpt_fail_all(struct client *client)
+lmtp_local_rcpt_fail_all(struct lmtp_local *local)
 {
-       struct lmtp_recipient *const *rcptp;
+       struct lmtp_local_recipient *const *rcptp;
 
-       array_foreach(&client->state.rcpt_to, rcptp) {
-               client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
-                                smtp_address_encode((*rcptp)->address));
+       array_foreach(&local->rcpt_to, rcptp) {
+               client_send_line(local->client, ERRSTR_TEMP_MAILBOX_FAIL,
+                                smtp_address_encode((*rcptp)->rcpt.address));
        }
 }
 
@@ -87,10 +157,10 @@ client_rcpt_fail_all(struct client *client)
  */
 
 static int
-lmtp_local_rcpt_check_quota(struct client *client,
-                          const struct lmtp_recipient *rcpt)
+lmtp_local_rcpt_check_quota(struct lmtp_local_recipient *rcpt)
 {
-       struct smtp_address *address = rcpt->address;
+       struct client *client = rcpt->rcpt.client;
+       struct smtp_address *address = rcpt->rcpt.address;
        struct mail_user *user;
        struct mail_namespace *ns;
        struct mailbox *box;
@@ -126,7 +196,7 @@ lmtp_local_rcpt_check_quota(struct client *client,
                if (ret < 0) {
                        errstr = mailbox_get_last_error(box, &error);
                        if (error == MAIL_ERROR_NOQUOTA) {
-                               client_send_line_overquota(client, rcpt, errstr);
+                               lmtp_local_rcpt_reply_overquota(rcpt, errstr);
                                ret = 0;
                        } else {
                                i_error("mailbox_get_status(%s, STATUS_CHECK_OVER_QUOTA) "
@@ -147,16 +217,16 @@ lmtp_local_rcpt_check_quota(struct client *client,
 }
 
 static bool
-lmtp_local_rcpt_anvil_finish(struct client *client,
-       struct lmtp_recipient *rcpt)
+lmtp_local_rcpt_anvil_finish(struct lmtp_local_recipient *rcpt)
 {
+       struct client *client = rcpt->rcpt.client;
        int ret;
 
-       if ((ret = lmtp_local_rcpt_check_quota(client, rcpt)) < 0) {
+       if ((ret = lmtp_local_rcpt_check_quota(rcpt)) < 0) {
                mail_storage_service_user_unref(&rcpt->service_user);
                return FALSE;
        }
-       array_append(&client->state.rcpt_to, &rcpt, 1);
+       array_append(&client->local->rcpt_to, &rcpt, 1);
        client_send_line(client, "250 2.1.5 OK");
        return TRUE;
 }
@@ -164,8 +234,8 @@ lmtp_local_rcpt_anvil_finish(struct client *client,
 static void
 lmtp_local_rcpt_anvil_cb(const char *reply, void *context)
 {
-       struct lmtp_recipient *rcpt = context;
-       struct client *client = rcpt->client;
+       struct lmtp_local_recipient *rcpt = context;
+       struct client *client = rcpt->rcpt.client;
        const struct mail_storage_service_input *input;
        unsigned int parallel_count = 0;
 
@@ -179,9 +249,9 @@ lmtp_local_rcpt_anvil_cb(const char *reply, void *context)
        if (parallel_count >= client->lmtp_set->lmtp_user_concurrency_limit) {
                client_send_line(client, ERRSTR_TEMP_USERDB_FAIL_PREFIX
                                 "Too many concurrent deliveries for user",
-                                smtp_address_encode(rcpt->address));
+                                smtp_address_encode(rcpt->rcpt.address));
                mail_storage_service_user_unref(&rcpt->service_user);
-       } else if (lmtp_local_rcpt_anvil_finish(client, rcpt)) {
+       } else if (lmtp_local_rcpt_anvil_finish(rcpt)) {
                rcpt->anvil_connect_sent = TRUE;
                input = mail_storage_service_user_get_input(rcpt->service_user);
                master_service_anvil_send(master_service, t_strconcat(
@@ -194,23 +264,24 @@ lmtp_local_rcpt_anvil_cb(const char *reply, void *context)
 }
 
 int lmtp_local_rcpt(struct client *client,
-       struct lmtp_recipient *rcpt,
        struct smtp_address *address,
-       const char *username, const char *detail)
+       const char *username, const char *detail,
+       const struct smtp_params_rcpt *params)
 {
+       struct lmtp_local_recipient *rcpt;
        struct mail_storage_service_input input;
-       const char *error = NULL;
+       struct mail_storage_service_user *service_user;
+       const char *session_id, *error = NULL;
        int ret;
 
        /* Use a unique session_id for each mail delivery. This is especially
           important for stats process to not see duplicate sessions. */
-       if (array_count(&client->state.rcpt_to) == 0)
-               rcpt->session_id = client->state.session_id;
+       if (client_get_rcpt_count(client) == 0)
+               session_id = client->state.session_id;
        else {
-               rcpt->session_id =
-                       p_strdup_printf(client->state_pool, "%s:%u",
-                                       client->state.session_id,
-                                       array_count(&client->state.rcpt_to)+1);
+               session_id =
+                       t_strdup_printf("%s:%u", client->state.session_id,
+                                       client_get_rcpt_count(client)+1);
        }
 
        i_zero(&input);
@@ -220,10 +291,10 @@ int lmtp_local_rcpt(struct client *client,
        input.remote_ip = client->remote_ip;
        input.local_port = client->local_port;
        input.remote_port = client->remote_port;
-       input.session_id = rcpt->session_id;
+       input.session_id = session_id;
 
        ret = mail_storage_service_lookup(storage_service, &input,
-                                         &rcpt->service_user, &error);
+                                         &service_user, &error);
 
        if (ret < 0) {
                i_error("Failed to lookup user %s: %s", username, error);
@@ -244,15 +315,23 @@ int lmtp_local_rcpt(struct client *client,
                client_send_line(client, "451 4.3.0 <%s> "
                        "Can't handle mixed proxy/non-proxy destinations",
                        smtp_address_encode(address));
-               mail_storage_service_user_unref(&rcpt->service_user);
+               mail_storage_service_user_unref(&service_user);
                return 0;
        }
 
-       rcpt->address = smtp_address_clone(client->state_pool, address);
+       if (client->local == NULL)
+               client->local = lmtp_local_init(client);
+
+       rcpt = p_new(client->state_pool, struct lmtp_local_recipient, 1);
+       rcpt->rcpt.client = client;
+       rcpt->rcpt.address = smtp_address_clone(client->state_pool, address); 
+       smtp_params_rcpt_copy(client->state_pool, &rcpt->rcpt.params, params);
        rcpt->detail = p_strdup(client->state_pool, detail);
+       rcpt->service_user = service_user;
+       rcpt->session_id = p_strdup(client->state_pool, session_id);
 
        if (client->lmtp_set->lmtp_user_concurrency_limit == 0) {
-               (void)lmtp_local_rcpt_anvil_finish(client, rcpt);
+               (void)lmtp_local_rcpt_anvil_finish(rcpt);
                return 0;
        } else {
                /* NOTE: username may change as the result of the userdb
@@ -275,12 +354,48 @@ int lmtp_local_rcpt(struct client *client,
  * DATA command
  */
 
+void lmtp_local_add_headers(struct lmtp_local *local,
+                           string_t *headers)
+{
+       struct client *client = local->client;
+       struct lmtp_local_recipient *const *rcpts;
+       const struct lmtp_settings *lmtp_set;
+       const struct smtp_address *rcpt_to = NULL;
+       unsigned int count;
+       void **sets;
+
+       str_printfa(headers, "Return-Path: <%s>\r\n",
+                   smtp_address_encode(client->state.mail_from));
+
+       rcpts = array_get(&local->rcpt_to, &count);
+       if (count == 1) {
+               sets = mail_storage_service_user_get_set(rcpts[0]->service_user);
+               lmtp_set = sets[3];
+
+               switch (lmtp_set->parsed_lmtp_hdr_delivery_address) {
+               case LMTP_HDR_DELIVERY_ADDRESS_NONE:
+                       break;
+               case LMTP_HDR_DELIVERY_ADDRESS_FINAL:
+                       rcpt_to = rcpts[0]->rcpt.address;
+                       break;
+               case LMTP_HDR_DELIVERY_ADDRESS_ORIGINAL:
+                       rcpt_to = rcpts[0]->rcpt.params.orcpt.addr;
+                       break;
+               }
+       }
+       if (rcpt_to != NULL) {
+               str_printfa(headers, "Delivered-To: %s\r\n",
+                       smtp_address_encode(rcpt_to));
+       }
+}
+
 static int
-lmtp_local_deliver(struct client *client,
-              const struct lmtp_recipient *rcpt,
-              struct mail *src_mail,
-              struct mail_deliver_session *session)
+lmtp_local_deliver(struct lmtp_local *local,
+                  struct lmtp_local_recipient *rcpt,
+                  struct mail *src_mail,
+                  struct mail_deliver_session *session)
 {
+       struct client *client = local->client;
        struct mail_storage_service_user *service_user = rcpt->service_user;
        struct mail_deliver_context dctx;
        struct mail_user *rcpt_user;
@@ -328,10 +443,10 @@ lmtp_local_deliver(struct client *client,
                                      &rcpt_user, &error) < 0) {
                i_error("Failed to initialize user: %s", error);
                client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
-                                smtp_address_encode(rcpt->address));
+                                smtp_address_encode(rcpt->rcpt.address));
                return -1;
        }
-       client->state.dest_user = rcpt_user;
+       local->rcpt_user = rcpt_user;
 
        sets = mail_storage_service_user_get_set(service_user);
        var_table = mail_user_var_expand_table(rcpt_user);
@@ -350,7 +465,7 @@ lmtp_local_deliver(struct client *client,
        if (ret <= 0) {
                i_error("Failed to expand settings: %s", error);
                client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
-                                smtp_address_encode(rcpt->address));
+                                smtp_address_encode(rcpt->rcpt.address));
                return -1;
        }
 
@@ -361,7 +476,7 @@ lmtp_local_deliver(struct client *client,
                i_error("Failed to expand mail_log_prefix=%s: %s",
                        rcpt_user->set->mail_log_prefix, error);
                client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
-                                smtp_address_encode(rcpt->address));
+                                smtp_address_encode(rcpt->rcpt.address));
                return -1;
        }
        i_set_failure_prefix("%s", str_c(str));
@@ -380,7 +495,7 @@ lmtp_local_deliver(struct client *client,
 
        /* RCPT TO */
        dctx.rcpt_user = rcpt_user;
-       dctx.rcpt_params = rcpt->params;
+       dctx.rcpt_params = rcpt->rcpt.params;
        if (dctx.rcpt_params.orcpt.addr != NULL) {
                /* used ORCPT */
        } else if (*dctx.set->lda_original_recipient_header != '\0') {
@@ -388,8 +503,8 @@ lmtp_local_deliver(struct client *client,
                                dctx.set->lda_original_recipient_header);
        }
        if (dctx.rcpt_params.orcpt.addr == NULL)
-               dctx.rcpt_params.orcpt.addr = rcpt->address;
-       dctx.rcpt_to = rcpt->address;
+               dctx.rcpt_params.orcpt.addr = rcpt->rcpt.address;
+       dctx.rcpt_to = rcpt->rcpt.address;
        if (*rcpt->detail == '\0' ||
            !client->lmtp_set->lmtp_save_to_detail_mailbox)
                dctx.rcpt_default_mailbox = "INBOX";
@@ -399,8 +514,8 @@ lmtp_local_deliver(struct client *client,
                        t_strconcat(ns->prefix, rcpt->detail, NULL);
        }
 
-       dctx.save_dest_mail = array_count(&client->state.rcpt_to) > 1 &&
-               client->state.first_saved_mail == NULL;
+       dctx.save_dest_mail = array_count(&local->rcpt_to) > 1 &&
+               local->first_saved_mail == NULL;
 
        dctx.session_time_msecs =
                timeval_diff_msecs(&client->state.data_end_timeval,
@@ -409,73 +524,75 @@ lmtp_local_deliver(struct client *client,
 
        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;
+                       i_assert(local->first_saved_mail == NULL);
+                       local->first_saved_mail = dctx.dest_mail;
                }
                client_send_line(client, "250 2.0.0 <%s> %s Saved",
-                                smtp_address_encode(rcpt->address),
+                                smtp_address_encode(rcpt->rcpt.address),
                                 rcpt->session_id);
                ret = 0;
        } else if (dctx.tempfail_error != NULL) {
                client_send_line(client, "451 4.2.0 <%s> %s",
-                                smtp_address_encode(rcpt->address),
+                                smtp_address_encode(rcpt->rcpt.address),
                                 dctx.tempfail_error);
                ret = -1;
        } else if (storage != NULL) {
                error = mail_storage_get_last_error(storage, &mail_error);
                if (mail_error == MAIL_ERROR_NOQUOTA) {
-                       client_send_line_overquota(client, rcpt, error);
+                       lmtp_local_rcpt_reply_overquota(rcpt, error);
                } else {
                        client_send_line(client, "451 4.2.0 <%s> %s",
-                                        smtp_address_encode(rcpt->address), error);
+                                        smtp_address_encode(rcpt->rcpt.address), error);
                }
                ret = -1;
        } else {
                /* This shouldn't happen */
                i_error("BUG: Saving failed to unknown storage");
                client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
-                                smtp_address_encode(rcpt->address));
+                                smtp_address_encode(rcpt->rcpt.address));
                ret = -1;
        }
        return ret;
 }
 
 static uid_t
-lmtp_local_deliver_to_rcpts(struct client *client,
+lmtp_local_deliver_to_rcpts(struct lmtp_local *local,
                            struct mail_deliver_session *session)
 {
+       struct client *client = local->client;
        uid_t first_uid = (uid_t)-1;
        struct mail *src_mail;
-       struct lmtp_recipient *const *rcpts;
+       struct lmtp_local_recipient *const *rcpts;
        unsigned int count, i;
        int ret;
-       src_mail = client->state.raw_mail;
 
-       rcpts = array_get(&client->state.rcpt_to, &count);
+       src_mail = local->raw_mail;
+
+       rcpts = array_get(&local->rcpt_to, &count);
        for (i = 0; i < count; i++) {
-               struct lmtp_recipient *rcpt = rcpts[i];
+               struct lmtp_local_recipient *rcpt = rcpts[i];
 
-               ret = lmtp_local_deliver(client, rcpt,
+               ret = lmtp_local_deliver(local, rcpt,
                                     src_mail, session);
                client_state_set(client, "DATA", "");
                i_set_failure_prefix("lmtp(%s): ", my_pid);
 
                /* succeeded and mail_user is not saved in first_saved_mail */
                if ((ret == 0 &&
-                    (client->state.first_saved_mail == NULL ||
-                     client->state.first_saved_mail == src_mail)) ||
+                    (local->first_saved_mail == NULL ||
+                     local->first_saved_mail == src_mail)) ||
                    /* failed. try the next one. */
-                   (ret != 0 && client->state.dest_user != NULL)) {
+                   (ret != 0 && local->rcpt_user != NULL)) {
                        if (i == (count - 1))
-                               mail_user_autoexpunge(client->state.dest_user);
-                       mail_user_unref(&client->state.dest_user);
+                               mail_user_autoexpunge(local->rcpt_user);
+                       mail_user_unref(&local->rcpt_user);
                } else if (ret == 0) {
                        /* use the first saved message to save it elsewhere too.
                           this might allow hard linking the files.
                           mail_user is saved in first_saved_mail,
                           will be unreferenced later on */
-                       client->state.dest_user = NULL;
-                       src_mail = client->state.first_saved_mail;
+                       local->rcpt_user = NULL;
+                       src_mail = local->first_saved_mail;
                        first_uid = geteuid();
                        i_assert(first_uid != 0);
                }
@@ -484,13 +601,14 @@ lmtp_local_deliver_to_rcpts(struct client *client,
 }
 
 static int
-lmtp_local_open_raw_mail(struct client *client,
+lmtp_local_open_raw_mail(struct lmtp_local *local,
                         struct istream *input)
 {
        static const char *wanted_headers[] = {
                "From", "To", "Message-ID", "Subject", "Return-Path",
                NULL
        };
+       struct client *client = local->client;
        struct mailbox *box;
        struct mailbox_transaction_context *mtrans;
        struct mailbox_header_lookup_ctx *headers_ctx;
@@ -502,34 +620,35 @@ lmtp_local_open_raw_mail(struct client *client,
                i_error("Can't open delivery mail as raw: %s",
                        mailbox_get_last_internal_error(box, &error));
                mailbox_free(&box);
-               client_rcpt_fail_all(client);
+               lmtp_local_rcpt_fail_all(local);
                return -1;
        }
 
        mtrans = mailbox_transaction_begin(box, 0, __func__);
 
        headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
-       client->state.raw_mail = mail_alloc(mtrans, 0, headers_ctx);
+       local->raw_mail = mail_alloc(mtrans, 0, headers_ctx);
        mailbox_header_lookup_unref(&headers_ctx);
-       mail_set_seq(client->state.raw_mail, 1);
+       mail_set_seq(local->raw_mail, 1);
        return 0;
 }
 
 void lmtp_local_data(struct client *client, struct istream *input)
 {
+       struct lmtp_local *local = client->local;
        struct mail_deliver_session *session;
        uid_t old_uid, first_uid;
 
-       if (lmtp_local_open_raw_mail(client, input) < 0)
+       if (lmtp_local_open_raw_mail(local, input) < 0)
                return;
 
        session = mail_deliver_session_init();
        old_uid = geteuid();
-       first_uid = lmtp_local_deliver_to_rcpts(client, session);
+       first_uid = lmtp_local_deliver_to_rcpts(local, session);
        mail_deliver_session_deinit(&session);
 
-       if (client->state.first_saved_mail != NULL) {
-               struct mail *mail = client->state.first_saved_mail;
+       if (local->first_saved_mail != NULL) {
+               struct mail *mail = local->first_saved_mail;
                struct mailbox_transaction_context *trans = mail->transaction;
                struct mailbox *box = trans->box;
                struct mail_user *user = box->storage->user;
index 82953caf751405d0d7c98b3f8d25bfa4cd186655..66bc7da7b2bb21130f0669bb6b52777eccf310f1 100644 (file)
@@ -2,16 +2,22 @@
 #define LMTP_LOCAL_H
 
 struct smtp_address;
-struct client;
+struct smtp_params_rcpt;
 struct lmtp_recipient;
-struct mail_deliver_session;
+struct lmtp_local;
+struct client;
 
-void lmtp_local_rcpt_deinit(struct lmtp_recipient *rcpt);
+unsigned int lmtp_local_rcpt_count(struct client *client);
+
+void lmtp_local_deinit(struct lmtp_local **_local);
 
 int lmtp_local_rcpt(struct client *client,
-       struct lmtp_recipient *rcpt,
        struct smtp_address *address,
-       const char *username, const char *detail);
+       const char *username, const char *detail,
+       const struct smtp_params_rcpt *params);
+
+void lmtp_local_add_headers(struct lmtp_local *local,
+                           string_t *headers);
 
 void lmtp_local_data(struct client *client, struct istream *input);
 
index 7e5342404c3f57d7794155a007337c544a8cb7b5..578eeb601011fa95834cb2ed67030a466bf2e795 100644 (file)
@@ -304,6 +304,13 @@ lmtp_proxy_write_reply(string_t *reply, const struct smtp_reply *proxy_reply)
  * RCPT command
  */
 
+unsigned int lmtp_proxy_rcpt_count(struct client *client)
+{
+       if (client->proxy == NULL)
+               return 0;
+       return array_count(&client->proxy->rcpt_to);
+}
+
 static bool
 lmtp_proxy_rcpt_parse_fields(struct lmtp_proxy_rcpt_settings *set,
                             const char *const *args, const char **address)
@@ -517,7 +524,8 @@ int lmtp_proxy_rcpt(struct client *client,
                pool_unref(&pool);
                return -1;
        }
-       if (array_count(&client->state.rcpt_to) != 0) {
+       if (client_get_rcpt_count(client) >
+               lmtp_proxy_rcpt_count(client)) {
                client_send_line(client, "451 4.3.0 <%s> "
                        "Can't handle mixed proxy/non-proxy destinations",
                        smtp_address_encode(address));
index 3469b505638f3a757bbd8d3d107c1fecc136ecc0..334780faf8bb55527cfdbfb7c2fbd34d06a57684 100644 (file)
@@ -37,6 +37,8 @@ lmtp_proxy_init(const struct lmtp_proxy_settings *set,
                struct ostream *client_output);
 void lmtp_proxy_deinit(struct lmtp_proxy **proxy);
 
+unsigned int lmtp_proxy_rcpt_count(struct client *client);
+
 /* Set the "MAIL FROM:" parameters */
 void lmtp_proxy_mail_from(struct lmtp_proxy *proxy,
                          const struct smtp_address *address,