/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream.h"
#include "istream-failure-at.h"
#include "istream-sized.h"
#include "istream-dot.h"
#include "smtp-parser.h"
#include "smtp-command-parser.h"
#include <ctype.h>
enum smtp_command_parser_state {
};
struct smtp_command_parser_state_data {
char *cmd_name;
char *cmd_params;
};
struct smtp_command_parser {
char *error;
};
enum smtp_command_parse_error code,
const char *format, ...)
{
}
struct smtp_command_parser *
const struct smtp_command_limits *limits)
{
}
}
}
return parser;
}
{
}
static void
{
}
{
}
}
static inline const char *_chr_sanitize(unsigned char c)
{
if (c >= 0x20 && c < 0x7F)
return t_strdup_printf("`%c'", c);
if (c == 0x0a)
return "<LF>";
if (c == 0x0d)
return "<CR>";
return t_strdup_printf("<0x%02x>", c);
}
{
const unsigned char *p;
/* The commands themselves are alphabetic characters.
*/
p++;
"Command name is too long");
return -1;
}
return 0;
return 1;
}
{
const unsigned char *p, *mp;
/* We assume parameters to match textstr
=> HT, SP, Printable US-ASCII
*/
p++;
"%s line is too long",
(parser->auth_response ?
"AUTH response" : "Command"));
return -1;
}
return 0;
/* In the interest of improved interoperability, SMTP receivers SHOULD
tolerate trailing white space before the terminating <CRLF>.
WSP = SP / HTAB ; white space
--> Trim the end of the buffer
*/
mp = p;
mp--;
}
"Duplicate space after command name");
return -1;
}
return 1;
}
static int
{
int ret;
/* RFC 5321, Section 4.1.1:
SMTP commands are character strings terminated by <CRLF>. The
commands themselves are alphabetic characters terminated by <SP> if
parameters follow and <CRLF> otherwise. (In the interest of improved
interoperability, SMTP receivers SHOULD tolerate trailing white space
before the terminating <CRLF>.)
*/
for (;;) {
if (parser->auth_response) {
/* parse AUTH response as bare parameters */
} else {
}
return 0;
if (parser->auth_response)
break;
/* fall through */
return ret;
return 0;
/* fall through */
break;
break;
"Unexpected character %s in command name",
return -1;
}
return 0;
/* fall through */
return ret;
return 0;
/* fall through */
"Unexpected character %s in %s",
(parser->auth_response ?
"AUTH response" :
"command parameters"));
return -1;
}
return 0;
/* fall through */
"Expected LF after CR at end of %s, "
"but found %s",
(parser->auth_response ?
"AUTH response" : "command"),
return -1;
}
return 1;
/* skip until end of line */
return 0;
break;
default:
i_unreached();
}
}
i_unreached();
return -1;
}
{
const unsigned char *begin;
int ret;
old_bytes)) > 0) {
if (ret != 0)
return ret;
}
if (ret == -2) {
/* should not really happen */
"%s line is too long",
(parser->auth_response ?
"AUTH response" : "Command"));
return -1;
}
if (ret < 0) {
ret = -2;
"Premature end of input");
} else {
"Stream error: %s",
}
}
return ret;
}
{
return FALSE;
}
static int
{
const unsigned char *data;
int ret;
return 1;
return 1;
}
case 0:
return 0;
case EIO:
"Invalid command data");
break;
case EMSGSIZE:
"Command data too large");
break;
default:
"Stream error while skipping command data: "
}
return -1;
}
return 1;
}
const char **cmd_name_r, const char **cmd_params_r,
const char **error_r)
{
int ret;
/* make sure we finished streaming payload from previous command
before we continue. */
if (ret < 0) {
}
return ret;
}
if (ret < 0) {
}
return ret;
}
return 1;
}
struct istream *
{
/* not supposed to happen; command should check size */
"Command data size exceeds maximum");
} else {
// FIXME: make exact_size stream type
}
}
struct istream *
{
"Command data size exceeds maximum");
} else {
}
}
const char **line_r,
const char **error_r)
{
int ret;
/* make sure we finished streaming payload from previous command
before we continue. */
if (ret < 0) {
}
return ret;
}
if (ret < 0) {
}
return ret;
}
return 1;
}