commands.c revision 7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2009-2010 Dovecot authors, see the included COPYING file */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#define ERRSTR_TEMP_MAILBOX_FAIL "451 4.3.0 <%s> Temporary internal error"
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen#define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> "
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ERRSTR_TEMP_USERDB_FAIL_PREFIX "Temporary user lookup failure"
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen#define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*30)
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainenint cmd_lhlo(struct client *client, const char *args)
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen const char *p;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen client_send_line(client, "501 Missing hostname");
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* domain / address-literal */
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen rfc822_parser_init(&parser, (const unsigned char *)args, strlen(args),
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-%s", client->my_domain);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-ENHANCEDSTATUSCODES");
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen client->state.lhlo = p_strdup(client->state_pool, str_c(domain));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_mail(struct client *client, const char *args)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int len;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL already given");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (strncasecmp(addr, "FROM:<", 6) != 0 || addr[len-1] != '>') {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen else if (strcasecmp(*argv, "BODY=8BITMIME") == 0)
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen "501 5.5.4 Unsupported options");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen p_strndup(client->state_pool, addr + 6, len - 7);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen p_array_init(&client->state.rcpt_to, client->state_pool, 64);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenclient_proxy_rcpt_parse_fields(struct lmtp_proxy_settings *set,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const char *const *args, const char **address)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* changing the username */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* just ignore it */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenclient_proxy_is_ourself(const struct client *client,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainenstatic const char *
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainenaddress_add_detail(struct client *client, const char *username,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen const char *delim = client->set->recipient_delimiter;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen return t_strconcat(username, delim, detail, NULL);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen return t_strconcat(username, delim, detail, domain, NULL);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenstatic bool client_proxy_rcpt(struct client *client, const char *address,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen const char *args, *const *fields, *errstr, *orig_username = username;
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen mail_storage_service_init_settings(storage_service, &input);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen info.service = master_service_get_name(master_service);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen pool = pool_alloconly_create("auth lookup", 1024);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen auth_conn = mail_storage_service_get_auth_conn(storage_service);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen ret = auth_master_pass_lookup(auth_conn, username, &info,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen errstr = ret < 0 && fields[0] != NULL ? t_strdup(fields[0]) :
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL, address);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* user not found from passdb. try userdb also. */
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (!client_proxy_rcpt_parse_fields(&set, fields, &username)) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* not proxying this user */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen /* username changed. change the address as well */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen address = address_add_detail(client, username, detail);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen } else if (client_proxy_is_ourself(client, &set)) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen i_error("Proxying to <%s> loops to itself", username);
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen if (array_count(&client->state.rcpt_to) != 0) {
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen "Can't handle mixed proxy/non-proxy destinations",
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client->proxy = lmtp_proxy_init(client->set->hostname,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen lmtp_proxy_mail_from(client->proxy, t_strdup_printf(
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_send_line(client, ERRSTR_TEMP_REMOTE_FAILURE);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainenstatic const char *lmtp_unescape_address(const char *name)
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen const char *p;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* quoted-string local-part. drop the quotes unless there's a
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen '@' character inside or there's an error. */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*p == '\0')
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*p == '\\') {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*p == '@')
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenstatic void rcpt_address_parse(struct client *client, const char *address,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char **username_r, const char **detail_r)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char *p, *p2;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (*client->set->recipient_delimiter == '\0')
f74f4098ee674df8e207e2bc3467e40c55d3b415Timo Sirainen p = strstr(address, client->set->recipient_delimiter);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen /* user+detail@domain */
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *username_r = t_strconcat(*username_r, p2, NULL);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rcpt(struct client *client, const char *args)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen const char *address, *username, *detail, *prefix;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int len;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL needed first");
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (strncasecmp(arg, "TO:<", 4) != 0 || arg[len-1] != '>') {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen address = lmtp_unescape_address(t_strndup(arg + 4, len - 5));
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen client_send_line(client, "501 5.5.4 Unsupported options");
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt_address_parse(client, address, &username, &detail);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (client_proxy_rcpt(client, address, username, detail))
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen "Can't handle mixed proxy/non-proxy destinations",
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = mail_storage_service_lookup(storage_service, &input,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen prefix = t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL_PREFIX,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen client_send_line(client, "%s%s", prefix, error);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen "550 5.1.1 <%s> User doesn't exist: %s",
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt.address = p_strdup(client->state_pool, address);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt.detail = p_strdup(client->state_pool, detail);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen array_append(&client->state.rcpt_to, &rcpt, 1);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_quit(struct client *client, const char *args ATTR_UNUSED)
ca598afa51b9c8ffd7c1460ac3c8bfa313c6d4afTimo Sirainen client_destroy(client, "221 2.0.0", "Client quit");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_vrfy(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "252 2.3.3 Try RCPT instead");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rset(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_noop(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenclient_deliver(struct client *client, const struct mail_recipient *rcpt,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const struct mail_storage_service_input *input;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen input = mail_storage_service_user_get_input(rcpt->service_user);
419be6cd72f6e11705576bbba683b29c32eaa762Timo Sirainen i_set_failure_prefix(t_strdup_printf("lmtp(%s, %s): ",
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (mail_storage_service_next(storage_service, rcpt->service_user,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen sets = mail_storage_service_user_get_set(rcpt->service_user);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.pool = pool_alloconly_create("mail delivery", 1024);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.src_envelope_sender = client->state.mail_from;
71564d36ea3aba6dd6a0d2560da46ffda733b679Timo Sirainen if (*dctx.set->lda_original_recipient_header != '\0') {
71564d36ea3aba6dd6a0d2560da46ffda733b679Timo Sirainen dctx.dest_addr = mail_deliver_get_address(src_mail,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen dctx.dest_mailbox_name = *rcpt->detail == '\0' ? "INBOX" : rcpt->detail;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.save_dest_mail = array_count(&client->state.rcpt_to) > 1 &&
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_assert(client->state.first_saved_mail == NULL);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.first_saved_mail = dctx.dest_mail;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen client_send_line(client, "250 2.0.0 <%s> %s Saved",
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* This shouldn't happen */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_error("BUG: Saving failed to unknown storage");
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen error = mail_storage_get_last_error(storage, &mail_error);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic bool client_deliver_next(struct client *client, struct mail *src_mail)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int count;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen rcpts = array_get(&client->state.rcpt_to, &count);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ret = client_deliver(client, &rcpts[client->state.rcpt_idx],
419be6cd72f6e11705576bbba683b29c32eaa762Timo Sirainen i_set_failure_prefix(t_strdup_printf("lmtp(%s): ", my_pid));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* failed. try the next one. */
efb0def040a3e98da05ea77c170cd6711a9c8747Timo Sirainenstatic void client_rcpt_fail_all(struct client *client)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic struct istream *client_get_input(struct client *client)
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen inputs[0] = i_stream_create_from_data(state->added_headers,
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen inputs[1] = i_stream_create_fd(state->mail_data_fd,
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen inputs[1] = i_stream_create_from_data(state->mail_data->data,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic int client_open_raw_mail(struct client *client, struct istream *input)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen static const char *wanted_headers[] = {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen "From", "To", "Message-ID", "Subject", "Return-Path",
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct mailbox_header_lookup_ctx *headers_ctx;
4143cfa11582989252741398b5ee0a6041d3da15Timo Sirainen box = mailbox_alloc(client->raw_mail_user->namespaces->list,
4143cfa11582989252741398b5ee0a6041d3da15Timo Sirainen "Dovecot Delivery Mail",
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_error("Can't open delivery mail as raw: %s",
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen mail_storage_get_last_error(box->storage, &error));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen raw_box->envelope_sender = client->state.mail_from;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.raw_trans = mailbox_transaction_begin(box, 0);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.raw_mail = mail_alloc(client->state.raw_trans,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenclient_input_data_write_local(struct client *client, struct istream *input)
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen while (client_deliver_next(client, src_mail)) {
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen /* use the first saved message to save it elsewhere too.
6b72856cca2917864b43d346b2aff987bb3397d2Timo Sirainen this might allow hard linking the files. */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mail *mail = client->state.first_saved_mail;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mailbox_transaction_context *trans = mail->transaction;
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen /* just in case these functions are going to write anything,
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen change uid back to user's own one */
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen /* switch back to running as root, since that's what we're
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen practically doing anyway. it's also important in case we
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen lose e.g. config connection and need to reconnect to it. */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic void client_input_data_finish(struct client *client)
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainenstatic void client_proxy_finish(bool timeout, void *context)
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainen t_strdup_printf("421 4.4.2 %s", client->my_domain),
b80e35ba6b14fc238e5f380861b895183fb842feTimo Sirainen "Disconnected for inactivity");
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainenstatic const char *client_get_added_headers(struct client *client)
8873384cf1429232ec1b44f5e856f6748c158607Timo Sirainen const char *host, *address = NULL, *username = NULL;
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen if (array_count(&client->state.rcpt_to) == 1) {
8873384cf1429232ec1b44f5e856f6748c158607Timo Sirainen rcpt_address_parse(client, address, &username, &detail);
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen str_printfa(str, "Return-Path: <%s>\r\n", client->state.mail_from);
8873384cf1429232ec1b44f5e856f6748c158607Timo Sirainen str_printfa(str, "Delivered-To: <%s>\r\n", username);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, "Received: from %s", client->state.lhlo);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if ((host = net_ip2addr(&client->remote_ip)) != NULL)
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, "\r\n\tby %s ("PACKAGE_NAME") with LMTP id %s",
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, "; %s\r\n", message_date_create(ioloop_time));
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic bool client_input_data_write(struct client *client)
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainenstatic int client_input_add_file(struct client *client,
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* continue writing to file */
b5babd4ea611616f0b3b2b9fb5917c78d1999a7bTimo Sirainen /* move everything to a temporary file. */
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen mail_user_set_get_temp_prefix(path, client->user_set);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen fd = safe_mkstemp_hostpid(path, 0600, (uid_t)-1, (gid_t)-1);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* we just want the fd, unlink it */
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* shouldn't happen.. */
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen i_error("unlink(%s) failed: %m", str_c(path));
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen state->mail_data_output = o_stream_create_fd_file(fd, 0, FALSE);
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen state->mail_data->data, state->mail_data->used);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen if (o_stream_send(client->state.mail_data_output,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenclient_input_add(struct client *client, const unsigned char *data, size_t size)
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen buffer_append(client->state.mail_data, data, size);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return client_input_add_file(client, data, size);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_input_data_handle(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const unsigned char *data;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen while ((ret = i_stream_read(client->dot_input)) > 0 || ret == -2) {
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen data = i_stream_get_data(client->dot_input, &size);
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen if (client_input_add(client, data, size) < 0) {
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen "Temporary internal failure");
85f8811e47003717620cbe066bb05494124308faTimo Sirainen /* client probably disconnected */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_input_data(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_data(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL needed first");
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (array_count(&client->state.rcpt_to) == 0 && client->proxy == NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "554 5.5.1 No valid recipients");
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen p_strdup(client->state_pool, client_get_added_headers(client));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.mail_data = buffer_create_dynamic(default_pool, 1024*64);
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen client->dot_input = i_stream_create_dot(client->input, TRUE);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (array_count(&client->state.rcpt_to) == 0) {