commands.c revision c4390dad33b03dd51ba2a475f550347c86ebdb9a
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#define ERRSTR_MAILBOX_TEMP_FAIL "451 4.2.0 <%s> Temporary internal error"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_lhlo(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-%s", client->my_domain);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-ENHANCEDSTATUSCODES");
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");
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen /* just skip these */
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);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic bool rcpt_is_duplicate(struct client *client, const char *name)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int i, count;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen rcpts = array_get(&client->state.rcpt_to, &count);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen for (i = 0; i < count; i++) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rcpt(struct client *client, const char *args)
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen const char *name, *error, *addr, *const *argv;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int len;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL needed first");
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen if (strncasecmp(addr, "TO:<", 4) != 0 || addr[len-1] != '>') {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250 2.1.5 OK, ignoring duplicate");
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen client_send_line(client, "501 5.5.4 Unsupported options");
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen ret = mail_storage_service_multi_lookup(multi_service, &input,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen "451 4.3.0 Temporary user lookup failure");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen rcpt.name = p_strdup(client->state_pool, name);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen array_append(&client->state.rcpt_to, &rcpt, 1);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_quit(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_destroy(client, "221 2.0.0", "Logged out");
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,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_set_failure_prefix(t_strdup_printf("lmtp(%s): ", rcpt->name));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (mail_storage_service_multi_next(multi_service, rcpt->multi_user,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, ERRSTR_MAILBOX_TEMP_FAIL, rcpt->name);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen sets = mail_storage_service_multi_user_get_set(rcpt->multi_user);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.pool = pool_alloconly_create("mail delivery", 1024);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.src_envelope_sender = client->state.mail_from;
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;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250 2.0.0 <%s> Saved", rcpt->name);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* This shouldn't happen */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_error("BUG: Saving failed to unknown storage");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, ERRSTR_MAILBOX_TEMP_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],
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* failed. try the next one. */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_rcpt_fail_all(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int i, count;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen rcpts = array_get(&client->state.rcpt_to, &count);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen for (i = 0; i < count; i++) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, ERRSTR_MAILBOX_TEMP_FAIL,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic int client_open_raw_mail(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen static const char *wanted_headers[] = {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen "From", "To", "Message-ID", "Subject", "Return-Path",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mailbox_list *raw_list = client->raw_mail_user->namespaces->list;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct mailbox_header_lookup_ctx *headers_ctx;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen o_stream_unref(&client->state.mail_data_output);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen input = i_stream_create_fd(client->state.mail_data_fd,
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen input = i_stream_create_from_data(client->state.mail_data->data,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen mailbox_alloc(raw_list, "Dovecot Delivery Mail", input,
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,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_input_data_finish(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->io = io_add(client->fd_in, IO_READ, client_input, client);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* save the message to the first recipient's mailbox */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* use the first saved message to save it elsewhere too.
315ce5be539bfe8bc7777ab0654499c49583cea2Timo 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;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainenstatic int client_input_add_file(struct client *client,
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* continue writing to file */
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen if (o_stream_send(client->state.mail_data_output,
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* move everything to a temporary file. FIXME: it really shouldn't
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen be in /tmp.. */
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));
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen client->state.mail_data_output = o_stream_create_fd_file(fd, 0, FALSE);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen o_stream_cork(client->state.mail_data_output);
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");
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");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (array_count(&client->state.rcpt_to) == 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "554 5.5.1 No valid recipients");
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);