From dac01ff6d788b20e5674e018a79f8a965b1e52bb Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Fri, 15 Nov 2013 16:10:05 +0000 Subject: [PATCH] smtp: Added support for NOOP and RSET commands --- lib/smtp.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++---- lib/smtp.h | 2 ++ 2 files changed, 92 insertions(+), 7 deletions(-) diff --git a/lib/smtp.c b/lib/smtp.c index e18947ec1..82ef3f2ed 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -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_parse_url_options(struct connectdata *conn); static CURLcode smtp_parse_url_path(struct connectdata *conn); +static CURLcode smtp_parse_custom_request(struct connectdata *conn); /* * SMTP protocol handler. @@ -314,6 +315,7 @@ static void state(struct connectdata *conn, smtpstate newstate) "AUTH_XOAUTH2", "AUTH_CANCEL", "AUTH_FINAL", + "COMMAND", "MAIL", "RCPT", "DATA", @@ -548,6 +550,28 @@ static CURLcode smtp_perform_authenticate(struct connectdata *conn) 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() @@ -1231,6 +1255,29 @@ static CURLcode smtp_state_auth_final_resp(struct connectdata *conn, 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 */ static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode, smtpstate instate) @@ -1433,6 +1480,10 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state); break; + case SMTP_COMMAND: + result = smtp_state_command_resp(conn, smtpcode, smtpc->state); + break; + case SMTP_MAIL: result = smtp_state_mail_resp(conn, smtpcode, smtpc->state); break; @@ -1596,7 +1647,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, conn->bits.close = TRUE; /* marked for closure */ 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 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. */ @@ -1645,31 +1696,38 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, * * smtp_perform() * - * This is the actual DO function for SMTP. Send a mail according to the - * options previously setup. + * This is the actual DO function for SMTP. Transfer a mail or send a command + * according to the options previously setup. */ static CURLcode smtp_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { /* This is SMTP and no proxy */ CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; 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 */ - struct SMTP *smtp = conn->data->req.protop; + struct SMTP *smtp = data->req.protop; smtp->transfer = FTPTRANSFER_INFO; } *dophase_done = FALSE; /* not done yet */ /* Start the first command in the DO phase */ - result = smtp_perform_mail(conn); + if(data->set.upload && data->set.mail_rcpt) + /* MAIL transfer */ + result = smtp_perform_mail(conn); + else + /* SMTP based command (NOOP or RSET) */ + result = smtp_perform_command(conn); + if(result) return result; - /* run the state-machine */ + /* Run the state-machine */ result = smtp_multi_statemach(conn, dophase_done); *connected = conn->bits.tcpconnect[FIRSTSOCKET]; @@ -1695,6 +1753,11 @@ static CURLcode smtp_do(struct connectdata *conn, bool *done) *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); 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); } +/*********************************************************************** + * + * 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) { /* When sending a SMTP payload we must detect CRLF. sequences making sure diff --git a/lib/smtp.h b/lib/smtp.h index 7d91657a4..4100f6b65 100644 --- a/lib/smtp.h +++ b/lib/smtp.h @@ -47,6 +47,7 @@ typedef enum { SMTP_AUTH_XOAUTH2, SMTP_AUTH_CANCEL, SMTP_AUTH_FINAL, + SMTP_COMMAND, /* NOOP and RSET */ SMTP_MAIL, /* MAIL FROM */ SMTP_RCPT, /* RCPT TO */ SMTP_DATA, @@ -61,6 +62,7 @@ typedef enum { used. */ struct SMTP { curl_pp_transfer transfer; + char *custom; /* Custom Request */ struct curl_slist *rcpt; /* Recipient list */ size_t eob; /* Number of bytes of the EOB (End Of Body) that have been received so far */