/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "array.h"
#include "istream.h"
#include "istream-chain.h"
#include "smtp-command-parser.h"
#include "smtp-server-private.h"
struct cmd_data_context {
};
{
// FIXME: should it even reply anything? RFC is unclear.
"Previous data chunk failed, issue RSET first");
return FALSE;
}
/* check valid MAIL */
503, "5.5.0", "MAIL needed first");
return FALSE;
}
/* Can only decide whether we have valid recipients once there are no
pending RCPT commands */
return TRUE;
/* special handling for LMTP */
/* check valid RCPT (at least one) */
/* RFC 2033, Section 4.3:
If there were no previously successful RCPT
commands in the mail transaction, then the
BDAT LAST command returns zero replies.
*/
} else {
/* RFC 2033, Section 4.2:
The additional restriction is that when there
have been no successful RCPT commands in the
mail transaction, the DATA command MUST fail
with a 503 reply code.
*/
503, "5.5.0", "No valid recipients");
}
return FALSE;
}
} else {
/* check valid RCPT (at least one) */
554, "5.5.0", "No valid recipients");
return FALSE;
}
}
return TRUE;
}
{
if (data_cmd->chunk_last ||
/* clean up */
}
}
{
}
{
/* reset state */
}
{
}
static void
{
/* re-check transaction state (for BDAT/B... command) */
return;
}
{
if (!data_cmd->client_input) {
if (!smtp_server_command_is_replied(command)) {
400, "4.0.0", "Failed to add data");
}
return;
}
"Connection lost during data transfer: "
"read(%s) failed: %s",
} else {
"Connection lost during data transfer: "
"Remote disconnected");
"Remote closed connection unexpectedly");
}
}
{
/* continue reading from client */
if (ret >= 0) {
"End of data");
} else if (!data_cmd->chunk_last &&
"End of chunk");
} else if (i_stream_get_data_size(
"Not all client data read");
} else {
}
} else {
return -1;
}
/* command is waiting for external event or it failed */
}
return 1;
}
{
(void)cmd_data_handle_input(cmd);
}
{
int ret;
/* this command is next to send a reply */
"Command is next to be replied");
/* check whether we have had successful mail and rcpt commands */
return;
/* LMTP 'DATA' and 'BDAT LAST' commands need to send one reply
per recipient
*/
}
/* chain data streams in the correct order */
if (data_cmd->chunk_last) {
"Seen the last chunk");
}
}
if (data_cmd->chunk_first) {
"First chunk");
/* command failed */
return;
}
if (!smtp_server_command_unref(&cmd_temp))
return;
}
} else {
if (data_cmd->client_input) {
/* using input from client connection;
capture I/O event */
}
(void)cmd_data_handle_input(cmd);
}
}
{
}
if (data_cmd->client_input)
if (data_cmd->chunk_last)
} else {
}
}
/* DATA command */
{
/* called when all previous commands were finished */
/* check whether we have had successful mail and rcpt commands */
return;
/* don't allow classic DATA when CHUNKING sequence was started before */
503, "5.5.0", "Bad sequence of commands");
return;
}
/* confirm initial success to client */
/* start reading message data from client */
}
const char *params)
{
/* data = "DATA" CRLF */
if (*params != '\0') {
501, "5.5.4", "Invalid parameters");
return;
}
}
/* BDAT/B... commands */
{
}
}
bool client_input)
{
return -1;
return 0;
}
/* BDAT command */
const char *params)
{
const char *const *argv;
502, "5.5.1", "Unsupported command");
return;
}
/* bdat-cmd = "BDAT" SP chunk-size [ SP end-marker ] CR LF
chunk-size = 1*DIGIT
end-marker = "LAST"
*/
501, "5.5.4", "Invalid chunk size parameter");
size = 0;
ret = -1;
501, "5.5.4", "Invalid parameters");
ret = -1;
501, "5.5.4", "Invalid end marker parameter");
ret = -1;
} else {
chunk_last = TRUE;
}
}
known */
size);
}
if (ret < 0) {
return;
}
}