smtp: Added support for NOOP and RSET commands

This commit is contained in:
Steve Holme 2013-11-15 16:10:05 +00:00
Родитель 4a9fe26837
Коммит dac01ff6d7
2 изменённых файлов: 92 добавлений и 7 удалений

Просмотреть файл

@ -104,6 +104,7 @@ static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
static CURLcode smtp_setup_connection(struct connectdata *conn); static CURLcode smtp_setup_connection(struct connectdata *conn);
static CURLcode smtp_parse_url_options(struct connectdata *conn); static CURLcode smtp_parse_url_options(struct connectdata *conn);
static CURLcode smtp_parse_url_path(struct connectdata *conn); static CURLcode smtp_parse_url_path(struct connectdata *conn);
static CURLcode smtp_parse_custom_request(struct connectdata *conn);
/* /*
* SMTP protocol handler. * SMTP protocol handler.
@ -314,6 +315,7 @@ static void state(struct connectdata *conn, smtpstate newstate)
"AUTH_XOAUTH2", "AUTH_XOAUTH2",
"AUTH_CANCEL", "AUTH_CANCEL",
"AUTH_FINAL", "AUTH_FINAL",
"COMMAND",
"MAIL", "MAIL",
"RCPT", "RCPT",
"DATA", "DATA",
@ -548,6 +550,28 @@ static CURLcode smtp_perform_authenticate(struct connectdata *conn)
return result; return result;
} }
/***********************************************************************
*
* smtp_perform_command()
*
* Sends a SMTP based command.
*/
static CURLcode smtp_perform_command(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
struct SMTP *smtp = data->req.protop;
/* Send the command */
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
smtp->custom && smtp->custom[0] != '\0' ?
smtp->custom : "NOOP");
if(!result)
state(conn, SMTP_COMMAND);
return result;
}
/*********************************************************************** /***********************************************************************
* *
* smtp_perform_mail() * smtp_perform_mail()
@ -1231,6 +1255,29 @@ static CURLcode smtp_state_auth_final_resp(struct connectdata *conn,
return result; return result;
} }
/* For command responses */
static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
smtpstate instate)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
struct SMTP *smtp = data->req.protop;
(void)instate; /* no use for this yet */
if(smtpcode/100 != 2) {
failf(data, "%s failed: %d",
smtp->custom && smtp->custom[0] != '\0' ? smtp->custom : "NOOP",
smtpcode);
result = CURLE_RECV_ERROR;
}
/* End of DO phase */
state(conn, SMTP_STOP);
return result;
}
/* For MAIL responses */ /* For MAIL responses */
static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode, static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
smtpstate instate) smtpstate instate)
@ -1433,6 +1480,10 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state); result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state);
break; break;
case SMTP_COMMAND:
result = smtp_state_command_resp(conn, smtpcode, smtpc->state);
break;
case SMTP_MAIL: case SMTP_MAIL:
result = smtp_state_mail_resp(conn, smtpcode, smtpc->state); result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
break; break;
@ -1596,7 +1647,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
conn->bits.close = TRUE; /* marked for closure */ conn->bits.close = TRUE; /* marked for closure */
result = status; /* use the already set error code */ result = status; /* use the already set error code */
} }
else if(!data->set.connect_only) { else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) {
/* Calculate the EOB taking into account any terminating CRLF from the /* Calculate the EOB taking into account any terminating CRLF from the
previous line of the email or the CRLF of the DATA command when there previous line of the email or the CRLF of the DATA command when there
is "no mail data". RFC-5321, sect. 4.1.1.4. */ is "no mail data". RFC-5321, sect. 4.1.1.4. */
@ -1645,31 +1696,38 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
* *
* smtp_perform() * smtp_perform()
* *
* This is the actual DO function for SMTP. Send a mail according to the * This is the actual DO function for SMTP. Transfer a mail or send a command
* options previously setup. * according to the options previously setup.
*/ */
static CURLcode smtp_perform(struct connectdata *conn, bool *connected, static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
bool *dophase_done) bool *dophase_done)
{ {
/* This is SMTP and no proxy */ /* This is SMTP and no proxy */
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
DEBUGF(infof(conn->data, "DO phase starts\n")); DEBUGF(infof(conn->data, "DO phase starts\n"));
if(conn->data->set.opt_no_body) { if(data->set.opt_no_body) {
/* Requested no body means no transfer */ /* Requested no body means no transfer */
struct SMTP *smtp = conn->data->req.protop; struct SMTP *smtp = data->req.protop;
smtp->transfer = FTPTRANSFER_INFO; smtp->transfer = FTPTRANSFER_INFO;
} }
*dophase_done = FALSE; /* not done yet */ *dophase_done = FALSE; /* not done yet */
/* Start the first command in the DO phase */ /* Start the first command in the DO phase */
if(data->set.upload && data->set.mail_rcpt)
/* MAIL transfer */
result = smtp_perform_mail(conn); result = smtp_perform_mail(conn);
else
/* SMTP based command (NOOP or RSET) */
result = smtp_perform_command(conn);
if(result) if(result)
return result; return result;
/* run the state-machine */ /* Run the state-machine */
result = smtp_multi_statemach(conn, dophase_done); result = smtp_multi_statemach(conn, dophase_done);
*connected = conn->bits.tcpconnect[FIRSTSOCKET]; *connected = conn->bits.tcpconnect[FIRSTSOCKET];
@ -1695,6 +1753,11 @@ static CURLcode smtp_do(struct connectdata *conn, bool *done)
*done = FALSE; /* default to false */ *done = FALSE; /* default to false */
/* Parse the custom request */
result = smtp_parse_custom_request(conn);
if(result)
return result;
result = smtp_regular_transfer(conn, done); result = smtp_regular_transfer(conn, done);
return result; return result;
@ -1910,6 +1973,26 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn)
return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE); return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
} }
/***********************************************************************
*
* smtp_parse_custom_request()
*
* Parse the custom request.
*/
static CURLcode smtp_parse_custom_request(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
struct SMTP *smtp = data->req.protop;
const char *custom = data->set.str[STRING_CUSTOMREQUEST];
/* URL decode the custom request */
if(custom)
result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE);
return result;
}
CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
{ {
/* When sending a SMTP payload we must detect CRLF. sequences making sure /* When sending a SMTP payload we must detect CRLF. sequences making sure

Просмотреть файл

@ -47,6 +47,7 @@ typedef enum {
SMTP_AUTH_XOAUTH2, SMTP_AUTH_XOAUTH2,
SMTP_AUTH_CANCEL, SMTP_AUTH_CANCEL,
SMTP_AUTH_FINAL, SMTP_AUTH_FINAL,
SMTP_COMMAND, /* NOOP and RSET */
SMTP_MAIL, /* MAIL FROM */ SMTP_MAIL, /* MAIL FROM */
SMTP_RCPT, /* RCPT TO */ SMTP_RCPT, /* RCPT TO */
SMTP_DATA, SMTP_DATA,
@ -61,6 +62,7 @@ typedef enum {
used. */ used. */
struct SMTP { struct SMTP {
curl_pp_transfer transfer; curl_pp_transfer transfer;
char *custom; /* Custom Request */
struct curl_slist *rcpt; /* Recipient list */ struct curl_slist *rcpt; /* Recipient list */
size_t eob; /* Number of bytes of the EOB (End Of Body) that size_t eob; /* Number of bytes of the EOB (End Of Body) that
have been received so far */ have been received so far */