aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/curl/lib/smtp.c
diff options
context:
space:
mode:
authorMaxim Yurchuk <maxim-yurchuk@ydb.tech>2024-10-18 20:31:38 +0300
committerGitHub <noreply@github.com>2024-10-18 20:31:38 +0300
commit2a74bac2d2d3bccb4e10120f1ead805640ec9dd0 (patch)
tree047e4818ced5aaf73f58517629e5260b5291f9f0 /contrib/libs/curl/lib/smtp.c
parent2d9656823e9521d8c29ea4c9a1d0eab78391abfc (diff)
parent3d834a1923bbf9403cd4a448e7f32b670aa4124f (diff)
downloadydb-2a74bac2d2d3bccb4e10120f1ead805640ec9dd0.tar.gz
Merge pull request #10502 from ydb-platform/mergelibs-241016-1210
Library import 241016-1210
Diffstat (limited to 'contrib/libs/curl/lib/smtp.c')
-rw-r--r--contrib/libs/curl/lib/smtp.c495
1 files changed, 234 insertions, 261 deletions
diff --git a/contrib/libs/curl/lib/smtp.c b/contrib/libs/curl/lib/smtp.c
index 3c5893284b..65fbc5b6c5 100644
--- a/contrib/libs/curl/lib/smtp.c
+++ b/contrib/libs/curl/lib/smtp.c
@@ -111,14 +111,13 @@ static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech,
const struct bufref *resp);
static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech);
static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out);
-static CURLcode cr_eob_add(struct Curl_easy *data);
/*
* SMTP protocol handler.
*/
const struct Curl_handler Curl_handler_smtp = {
- "smtp", /* scheme */
+ "SMTP", /* scheme */
smtp_setup_connection, /* setup_connection */
smtp_do, /* do_it */
smtp_done, /* done */
@@ -131,8 +130,7 @@ const struct Curl_handler Curl_handler_smtp = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smtp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMTP, /* defport */
@@ -148,7 +146,7 @@ const struct Curl_handler Curl_handler_smtp = {
*/
const struct Curl_handler Curl_handler_smtps = {
- "smtps", /* scheme */
+ "SMTPS", /* scheme */
smtp_setup_connection, /* setup_connection */
smtp_do, /* do_it */
smtp_done, /* done */
@@ -161,8 +159,7 @@ const struct Curl_handler Curl_handler_smtps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smtp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMTPS, /* defport */
@@ -253,8 +250,8 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
*/
static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
{
- char *message = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf);
- size_t len = data->conn->proto.smtpc.pp.nfinal;
+ char *message = data->state.buffer;
+ size_t len = strlen(message);
if(len > 4) {
/* Find the start of the message */
@@ -288,7 +285,7 @@ static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
static void smtp_state(struct Curl_easy *data, smtpstate newstate)
{
struct smtp_conn *smtpc = &data->conn->proto.smtpc;
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* for debug purposes */
static const char * const names[] = {
"STOP",
@@ -308,8 +305,8 @@ static void smtp_state(struct Curl_easy *data, smtpstate newstate)
};
if(smtpc->state != newstate)
- CURL_TRC_SMTP(data, "state change from %s to %s",
- names[smtpc->state], names[newstate]);
+ infof(data, "SMTP %p state change from %s to %s",
+ (void *)smtpc, names[smtpc->state], names[newstate]);
#endif
smtpc->state = newstate;
@@ -534,16 +531,16 @@ static CURLcode smtp_perform_command(struct Curl_easy *data)
if(smtp->rcpt) {
/* We notify the server we are sending UTF-8 data if a) it supports the
SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
- either the local address or hostname parts. This is regardless of
- whether the hostname is encoded using IDN ACE */
+ either the local address or host name parts. This is regardless of
+ whether the host name is encoded using IDN ACE */
bool utf8 = FALSE;
if((!smtp->custom) || (!smtp->custom[0])) {
char *address = NULL;
struct hostname host = { NULL, NULL, NULL, NULL };
- /* Parse the mailbox to verify into the local address and hostname
- parts, converting the hostname to an IDN A-label if necessary */
+ /* Parse the mailbox to verify into the local address and host name
+ parts, converting the host name to an IDN A-label if necessary */
result = smtp_parse_address(smtp->rcpt->data,
&address, &host);
if(result)
@@ -555,7 +552,7 @@ static CURLcode smtp_perform_command(struct Curl_easy *data)
((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
(!Curl_is_ASCII_name(host.name)));
- /* Send the VRFY command (Note: The hostname part may be absent when the
+ /* Send the VRFY command (Note: The host name part may be absent when the
host is a local system) */
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "VRFY %s%s%s%s",
address,
@@ -607,8 +604,8 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
/* We notify the server we are sending UTF-8 data if a) it supports the
SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
- either the local address or hostname parts. This is regardless of
- whether the hostname is encoded using IDN ACE */
+ either the local address or host name parts. This is regardless of
+ whether the host name is encoded using IDN ACE */
bool utf8 = FALSE;
/* Calculate the FROM parameter */
@@ -616,12 +613,12 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
char *address = NULL;
struct hostname host = { NULL, NULL, NULL, NULL };
- /* Parse the FROM mailbox into the local address and hostname parts,
- converting the hostname to an IDN A-label if necessary */
+ /* Parse the FROM mailbox into the local address and host name parts,
+ converting the host name to an IDN A-label if necessary */
result = smtp_parse_address(data->set.str[STRING_MAIL_FROM],
&address, &host);
if(result)
- goto out;
+ return result;
/* Establish whether we should report SMTPUTF8 to the server for this
mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
@@ -635,8 +632,8 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
Curl_free_idnconverted_hostname(&host);
}
else
- /* An invalid mailbox was provided but we will simply let the server
- worry about that and reply with a 501 error */
+ /* An invalid mailbox was provided but we'll simply let the server worry
+ about that and reply with a 501 error */
from = aprintf("<%s>", address);
free(address);
@@ -645,10 +642,8 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
/* Null reverse-path, RFC-5321, sect. 3.6.3 */
from = strdup("<>");
- if(!from) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
+ if(!from)
+ return CURLE_OUT_OF_MEMORY;
/* Calculate the optional AUTH parameter */
if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
@@ -656,12 +651,14 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
char *address = NULL;
struct hostname host = { NULL, NULL, NULL, NULL };
- /* Parse the AUTH mailbox into the local address and hostname parts,
- converting the hostname to an IDN A-label if necessary */
+ /* Parse the AUTH mailbox into the local address and host name parts,
+ converting the host name to an IDN A-label if necessary */
result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH],
&address, &host);
- if(result)
- goto out;
+ if(result) {
+ free(from);
+ return result;
+ }
/* Establish whether we should report SMTPUTF8 to the server for this
mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
@@ -676,9 +673,10 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
Curl_free_idnconverted_hostname(&host);
}
else
- /* An invalid mailbox was provided but we will simply let the server
+ /* An invalid mailbox was provided but we'll simply let the server
worry about it */
auth = aprintf("<%s>", address);
+
free(address);
}
else
@@ -686,16 +684,16 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
auth = strdup("<>");
if(!auth) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
+ free(from);
+
+ return CURLE_OUT_OF_MEMORY;
}
}
-#ifndef CURL_DISABLE_MIME
/* Prepare the mime data if some. */
if(data->set.mimepost.kind != MIMEKIND_NONE) {
/* Use the whole structure as data. */
- data->set.mimepost.flags &= ~(unsigned int)MIME_BODY_ONLY;
+ data->set.mimepost.flags &= ~MIME_BODY_ONLY;
/* Add external headers and mime version. */
curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
@@ -707,31 +705,37 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
"Mime-Version: 1.0");
+ /* Make sure we will read the entire mime structure. */
if(!result)
- result = Curl_creader_set_mime(data, &data->set.mimepost);
- if(result)
- goto out;
- data->state.infilesize = Curl_creader_total_length(data);
- }
- else
-#endif
- {
- result = Curl_creader_set_fread(data, data->state.infilesize);
- if(result)
- goto out;
+ result = Curl_mime_rewind(&data->set.mimepost);
+
+ if(result) {
+ free(from);
+ free(auth);
+
+ return result;
+ }
+
+ data->state.infilesize = Curl_mime_size(&data->set.mimepost);
+
+ /* Read from mime structure. */
+ data->state.fread_func = (curl_read_callback) Curl_mime_read;
+ data->state.in = (void *) &data->set.mimepost;
}
/* Calculate the optional SIZE parameter */
if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
- size = aprintf("%" FMT_OFF_T, data->state.infilesize);
+ size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
if(!size) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
+ free(from);
+ free(auth);
+
+ return CURLE_OUT_OF_MEMORY;
}
}
- /* If the mailboxes in the FROM and AUTH parameters do not include a UTF-8
+ /* If the mailboxes in the FROM and AUTH parameters don't include a UTF-8
based address then quickly scan through the recipient list and check if
any there do, as we need to correctly identify our support for SMTPUTF8
in the envelope, as per RFC-6531 sect. 3.4 */
@@ -740,7 +744,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
struct curl_slist *rcpt = smtp->rcpt;
while(rcpt && !utf8) {
- /* Does the hostname contain non-ASCII characters? */
+ /* Does the host name contain non-ASCII characters? */
if(!Curl_is_ASCII_name(rcpt->data))
utf8 = TRUE;
@@ -748,11 +752,6 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
}
}
- /* Add the client reader doing STMP EOB escaping */
- result = cr_eob_add(data);
- if(result)
- goto out;
-
/* Send the MAIL command */
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
"MAIL FROM:%s%s%s%s%s%s",
@@ -764,7 +763,6 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
utf8 ? " SMTPUTF8" /* Internationalised mailbox */
: ""); /* included in our envelope */
-out:
free(from);
free(auth);
free(size);
@@ -790,8 +788,8 @@ static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data)
char *address = NULL;
struct hostname host = { NULL, NULL, NULL, NULL };
- /* Parse the recipient mailbox into the local address and hostname parts,
- converting the hostname to an IDN A-label if necessary */
+ /* Parse the recipient mailbox into the local address and host name parts,
+ converting the host name to an IDN A-label if necessary */
result = smtp_parse_address(smtp->rcpt->data,
&address, &host);
if(result)
@@ -802,7 +800,7 @@ static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data)
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s@%s>",
address, host.name);
else
- /* An invalid mailbox was provided but we will simply let the server worry
+ /* An invalid mailbox was provided but we'll simply let the server worry
about that and reply with a 501 error */
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s>",
address);
@@ -861,7 +859,7 @@ static CURLcode smtp_state_starttls_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
/* Pipelining in response is forbidden. */
- if(data->conn->proto.smtpc.pp.overflow)
+ if(data->conn->proto.smtpc.pp.cache_size)
return CURLE_WEIRD_SERVER_REPLY;
if(smtpcode != 220) {
@@ -885,8 +883,8 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- const char *line = Curl_dyn_ptr(&smtpc->pp.recvbuf);
- size_t len = smtpc->pp.nfinal;
+ const char *line = data->state.buffer;
+ size_t len = strlen(line);
(void)instate; /* no use for this yet */
@@ -958,7 +956,7 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
if(smtpcode != 1) {
if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
- /* We do not have a SSL/TLS connection yet, but SSL is requested */
+ /* We don't have a SSL/TLS connection yet, but SSL is requested */
if(smtpc->tls_supported)
/* Switch to TLS connection now */
result = smtp_perform_starttls(data, conn);
@@ -1035,8 +1033,8 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
{
CURLcode result = CURLE_OK;
struct SMTP *smtp = data->req.p.smtp;
- char *line = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf);
- size_t len = data->conn->proto.smtpc.pp.nfinal;
+ char *line = data->state.buffer;
+ size_t len = strlen(line);
(void)instate; /* no use for this yet */
@@ -1046,8 +1044,12 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
result = CURLE_WEIRD_SERVER_REPLY;
}
else {
- if(!data->req.no_body)
- result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
+ /* Temporarily add the LF character back and send as body to the client */
+ if(!data->req.no_body) {
+ line[len] = '\n';
+ result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1);
+ line[len] = '\0';
+ }
if(smtpcode != 1) {
if(smtp->rcpt) {
@@ -1102,7 +1104,7 @@ static CURLcode smtp_state_rcpt_resp(struct Curl_easy *data,
is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE;
- /* If there is multiple RCPT TO to be issued, it is possible to ignore errors
+ /* If there's multiple RCPT TO to be issued, it's possible to ignore errors
and proceed with only the valid addresses. */
is_smtp_blocking_err =
(is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE;
@@ -1129,7 +1131,7 @@ static CURLcode smtp_state_rcpt_resp(struct Curl_easy *data,
/* Send the next RCPT TO command */
result = smtp_perform_rcpt_to(data);
else {
- /* We were not able to issue a successful RCPT TO command while going
+ /* We weren't able to issue a successful RCPT TO command while going
over recipients (potentially multiple). Sending back last error. */
if(!smtp->rcpt_had_ok) {
failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error);
@@ -1164,7 +1166,7 @@ static CURLcode smtp_state_data_resp(struct Curl_easy *data, int smtpcode,
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* SMTP upload */
- Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
/* End of DO phase */
smtp_state(data, SMTP_STOP);
@@ -1196,13 +1198,13 @@ static CURLcode smtp_statemachine(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
int smtpcode;
struct smtp_conn *smtpc = &conn->proto.smtpc;
struct pingpong *pp = &smtpc->pp;
size_t nread = 0;
/* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
-upgrade_tls:
if(smtpc->state == SMTP_UPGRADETLS)
return smtp_perform_upgrade_tls(data);
@@ -1212,7 +1214,7 @@ upgrade_tls:
do {
/* Read the response from the server */
- result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &smtpcode, &nread);
+ result = Curl_pp_readresp(data, sock, pp, &smtpcode, &nread);
if(result)
return result;
@@ -1239,10 +1241,6 @@ upgrade_tls:
case SMTP_STARTTLS:
result = smtp_state_starttls_resp(data, smtpcode, smtpc->state);
- /* During UPGRADETLS, leave the read loop as we need to connect
- * (e.g. TLS handshake) before we continue sending/receiving. */
- if(!result && (smtpc->state == SMTP_UPGRADETLS))
- goto upgrade_tls;
break;
case SMTP_AUTH:
@@ -1270,6 +1268,7 @@ upgrade_tls:
break;
case SMTP_QUIT:
+ /* fallthrough, just stop! */
default:
/* internal error */
smtp_state(data, SMTP_STOP);
@@ -1363,7 +1362,8 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
Curl_sasl_init(&smtpc->sasl, data, &saslsmtp);
/* Initialise the pingpong layer */
- Curl_pp_init(pp);
+ Curl_pp_setup(pp);
+ Curl_pp_init(data, pp);
/* Parse the URL options */
result = smtp_parse_url_options(conn);
@@ -1398,6 +1398,10 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct SMTP *smtp = data->req.p.smtp;
+ struct pingpong *pp = &conn->proto.smtpc.pp;
+ char *eob;
+ ssize_t len;
+ ssize_t bytes_written;
(void)premature;
@@ -1412,7 +1416,47 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
result = status; /* use the already set error code */
}
else if(!data->set.connect_only && data->set.mail_rcpt &&
- (data->state.upload || IS_MIME_POST(data))) {
+ (data->state.upload || data->set.mimepost.kind)) {
+ /* 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.
+
+ Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to
+ fail when using a different pointer following a previous write, that
+ returned CURLE_AGAIN, we duplicate the EOB now rather than when the
+ bytes written doesn't equal len. */
+ if(smtp->trailing_crlf || !data->state.infilesize) {
+ eob = strdup(&SMTP_EOB[2]);
+ len = SMTP_EOB_LEN - 2;
+ }
+ else {
+ eob = strdup(SMTP_EOB);
+ len = SMTP_EOB_LEN;
+ }
+
+ if(!eob)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the end of block data */
+ result = Curl_write(data, conn->writesockfd, eob, len, &bytes_written);
+ if(result) {
+ free(eob);
+ return result;
+ }
+
+ if(bytes_written != len) {
+ /* The whole chunk was not sent so keep it around and adjust the
+ pingpong structure accordingly */
+ pp->sendthis = eob;
+ pp->sendsize = len;
+ pp->sendleft = len - bytes_written;
+ }
+ else {
+ /* Successfully sent so adjust the response timeout relative to now */
+ pp->response = Curl_now();
+
+ free(eob);
+ }
smtp_state(data, SMTP_POSTDATA);
@@ -1422,8 +1466,7 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
/* Clear the transfer mode for the next request */
smtp->transfer = PPTRANSFER_BODY;
- CURL_TRC_SMTP(data, "smtp_done(status=%d, premature=%d) -> %d",
- status, premature, result);
+
return result;
}
@@ -1441,7 +1484,7 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
CURLcode result = CURLE_OK;
struct SMTP *smtp = data->req.p.smtp;
- CURL_TRC_SMTP(data, "smtp_perform(), start");
+ DEBUGF(infof(data, "DO phase starts"));
if(data->req.no_body) {
/* Requested no body means no transfer */
@@ -1453,10 +1496,10 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
/* Store the first recipient (or NULL if not specified) */
smtp->rcpt = data->set.mail_rcpt;
- /* Track of whether we have successfully sent at least one RCPT TO command */
+ /* Track of whether we've successfully sent at least one RCPT TO command */
smtp->rcpt_had_ok = FALSE;
- /* Track of the last error we have received by sending RCPT TO command */
+ /* Track of the last error we've received by sending RCPT TO command */
smtp->rcpt_last_error = 0;
/* Initial data character is the first character in line: it is implicitly
@@ -1465,7 +1508,7 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
smtp->eob = 2;
/* Start the first command in the DO phase */
- if((data->state.upload || IS_MIME_POST(data)) && data->set.mail_rcpt)
+ if((data->state.upload || data->set.mimepost.kind) && data->set.mail_rcpt)
/* MAIL transfer */
result = smtp_perform_mail(data);
else
@@ -1473,16 +1516,16 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
result = smtp_perform_command(data);
if(result)
- goto out;
+ return result;
/* Run the state-machine */
result = smtp_multi_statemach(data, dophase_done);
*connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
-out:
- CURL_TRC_SMTP(data, "smtp_perform() -> %d, connected=%d, done=%d",
- result, *connected, *dophase_done);
+ if(*dophase_done)
+ DEBUGF(infof(data, "DO phase is complete"));
+
return result;
}
@@ -1498,8 +1541,6 @@ out:
static CURLcode smtp_do(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
- DEBUGASSERT(data);
- DEBUGASSERT(data->conn);
*done = FALSE; /* default to false */
/* Parse the custom request */
@@ -1508,7 +1549,7 @@ static CURLcode smtp_do(struct Curl_easy *data, bool *done)
return result;
result = smtp_regular_transfer(data, done);
- CURL_TRC_SMTP(data, "smtp_do() -> %d, done=%d", result, *done);
+
return result;
}
@@ -1543,7 +1584,6 @@ static CURLcode smtp_disconnect(struct Curl_easy *data,
/* Cleanup our connection based variables */
Curl_safefree(smtpc->domain);
- CURL_TRC_SMTP(data, "smtp_disconnect(), finished");
return CURLE_OK;
}
@@ -1557,7 +1597,7 @@ static CURLcode smtp_dophase_done(struct Curl_easy *data, bool connected)
if(smtp->transfer != PPTRANSFER_BODY)
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
return CURLE_OK;
}
@@ -1575,7 +1615,6 @@ static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done)
DEBUGF(infof(data, "DO phase is complete"));
}
- CURL_TRC_SMTP(data, "smtp_doing() -> %d, done=%d", result, *dophase_done);
return result;
}
@@ -1610,8 +1649,6 @@ static CURLcode smtp_regular_transfer(struct Curl_easy *data,
if(!result && *dophase_done)
result = smtp_dophase_done(data, connected);
- CURL_TRC_SMTP(data, "smtp_regular_transfer() -> %d, done=%d",
- result, *dophase_done);
return result;
}
@@ -1625,8 +1662,10 @@ static CURLcode smtp_setup_connection(struct Curl_easy *data,
/* Initialise the SMTP layer */
result = smtp_init(data);
- CURL_TRC_SMTP(data, "smtp_setup_connection() -> %d", result);
- return result;
+ if(result)
+ return result;
+
+ return CURLE_OK;
}
/***********************************************************************
@@ -1716,7 +1755,7 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data)
* smtp_parse_address()
*
* Parse the fully qualified mailbox address into a local address part and the
- * hostname, converting the hostname to an IDN A-label, as per RFC-5890, if
+ * host name, converting the host name to an IDN A-label, as per RFC-5890, if
* necessary.
*
* Parameters:
@@ -1727,8 +1766,8 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data)
* address [in/out] - A new allocated buffer which holds the local
* address part of the mailbox. This buffer must be
* free'ed by the caller.
- * host [in/out] - The hostname structure that holds the original,
- * and optionally encoded, hostname.
+ * host [in/out] - The host name structure that holds the original,
+ * and optionally encoded, host name.
* Curl_free_idnconverted_hostname() must be called
* once the caller has finished with the structure.
*
@@ -1736,14 +1775,14 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data)
*
* Notes:
*
- * Should a UTF-8 hostname require conversion to IDN ACE and we cannot honor
+ * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor
* that conversion then we shall return success. This allow the caller to send
* the data to the server as a U-label (as per RFC-6531 sect. 3.2).
*
* If an mailbox '@' separator cannot be located then the mailbox is considered
* to be either a local mailbox or an invalid mailbox (depending on what the
* calling function deems it to be) then the input will simply be returned in
- * the address part with the hostname being NULL.
+ * the address part with the host name being NULL.
*/
static CURLcode smtp_parse_address(const char *fqma, char **address,
struct hostname *host)
@@ -1752,7 +1791,7 @@ static CURLcode smtp_parse_address(const char *fqma, char **address,
size_t length;
/* Duplicate the fully qualified email address so we can manipulate it,
- ensuring it does not contain the delimiters if specified */
+ ensuring it doesn't contain the delimiters if specified */
char *dup = strdup(fqma[0] == '<' ? fqma + 1 : fqma);
if(!dup)
return CURLE_OUT_OF_MEMORY;
@@ -1763,17 +1802,17 @@ static CURLcode smtp_parse_address(const char *fqma, char **address,
dup[length - 1] = '\0';
}
- /* Extract the hostname from the address (if we can) */
+ /* Extract the host name from the address (if we can) */
host->name = strpbrk(dup, "@");
if(host->name) {
*host->name = '\0';
host->name = host->name + 1;
- /* Attempt to convert the hostname to IDN ACE */
+ /* Attempt to convert the host name to IDN ACE */
(void) Curl_idnconvert_hostname(host);
/* If Curl_idnconvert_hostname() fails then we shall attempt to continue
- and send the hostname using UTF-8 rather than as 7-bit ACE (which is
+ and send the host name using UTF-8 rather than as 7-bit ACE (which is
our preference) */
}
@@ -1783,174 +1822,108 @@ static CURLcode smtp_parse_address(const char *fqma, char **address,
return result;
}
-struct cr_eob_ctx {
- struct Curl_creader super;
- struct bufq buf;
- size_t n_eob; /* how many EOB bytes we matched so far */
- size_t eob; /* Number of bytes of the EOB (End Of Body) that
- have been received so far */
- BIT(read_eos); /* we read an EOS from the next reader */
- BIT(eos); /* we have returned an EOS */
-};
-
-static CURLcode cr_eob_init(struct Curl_easy *data,
- struct Curl_creader *reader)
+CURLcode Curl_smtp_escape_eob(struct Curl_easy *data,
+ const ssize_t nread,
+ const ssize_t offset)
{
- struct cr_eob_ctx *ctx = reader->ctx;
- (void)data;
- /* The first char we read is the first on a line, as if we had
- * read CRLF just before */
- ctx->n_eob = 2;
- Curl_bufq_init2(&ctx->buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT);
- return CURLE_OK;
-}
-
-static void cr_eob_close(struct Curl_easy *data, struct Curl_creader *reader)
-{
- struct cr_eob_ctx *ctx = reader->ctx;
- (void)data;
- Curl_bufq_free(&ctx->buf);
-}
-
-/* this is the 5-bytes End-Of-Body marker for SMTP */
-#define SMTP_EOB "\r\n.\r\n"
-#define SMTP_EOB_FIND_LEN 3
-
-/* client reader doing SMTP End-Of-Body escaping. */
-static CURLcode cr_eob_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *pnread, bool *peos)
-{
- struct cr_eob_ctx *ctx = reader->ctx;
- CURLcode result = CURLE_OK;
- size_t nread, i, start, n;
- bool eos;
+ /* When sending a SMTP payload we must detect CRLF. sequences making sure
+ they are sent as CRLF.. instead, as a . on the beginning of a line will
+ be deleted by the server when not part of an EOB terminator and a
+ genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
+ data by the server
+ */
+ ssize_t i;
+ ssize_t si;
+ struct SMTP *smtp = data->req.p.smtp;
+ char *scratch = data->state.scratch;
+ char *newscratch = NULL;
+ char *oldscratch = NULL;
+ size_t eob_sent;
- if(!ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
- /* Get more and convert it when needed */
- result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
- if(result)
- return result;
+ /* Do we need to allocate a scratch buffer? */
+ if(!scratch || data->set.crlf) {
+ oldscratch = scratch;
- ctx->read_eos = eos;
- if(nread) {
- if(!ctx->n_eob && !memchr(buf, SMTP_EOB[0], nread)) {
- /* not in the middle of a match, no EOB start found, just pass */
- *pnread = nread;
- *peos = FALSE;
- return CURLE_OK;
- }
- /* scan for EOB (continuation) and convert */
- for(i = start = 0; i < nread; ++i) {
- if(ctx->n_eob >= SMTP_EOB_FIND_LEN) {
- /* matched the EOB prefix and seeing additional char, add '.' */
- result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
- if(result)
- return result;
- result = Curl_bufq_cwrite(&ctx->buf, ".", 1, &n);
- if(result)
- return result;
- ctx->n_eob = 0;
- start = i;
- if(data->state.infilesize > 0)
- data->state.infilesize++;
- }
+ scratch = newscratch = malloc(2 * data->set.upload_buffer_size);
+ if(!newscratch) {
+ failf(data, "Failed to alloc scratch buffer");
- if(buf[i] != SMTP_EOB[ctx->n_eob])
- ctx->n_eob = 0;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ DEBUGASSERT((size_t)data->set.upload_buffer_size >= (size_t)nread);
+
+ /* Have we already sent part of the EOB? */
+ eob_sent = smtp->eob;
+
+ /* This loop can be improved by some kind of Boyer-Moore style of
+ approach but that is saved for later... */
+ if(offset)
+ memcpy(scratch, data->req.upload_fromhere, offset);
+ for(i = offset, si = offset; i < nread; i++) {
+ if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
+ smtp->eob++;
+
+ /* Is the EOB potentially the terminating CRLF? */
+ if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
+ smtp->trailing_crlf = TRUE;
+ else
+ smtp->trailing_crlf = FALSE;
+ }
+ else if(smtp->eob) {
+ /* A previous substring matched so output that first */
+ memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
+ si += smtp->eob - eob_sent;
+
+ /* Then compare the first byte */
+ if(SMTP_EOB[0] == data->req.upload_fromhere[i])
+ smtp->eob = 1;
+ else
+ smtp->eob = 0;
- if(buf[i] == SMTP_EOB[ctx->n_eob]) {
- /* matching another char of the EOB */
- ++ctx->n_eob;
- }
- }
+ eob_sent = 0;
- /* add any remainder to buf */
- if(start < nread) {
- result = Curl_bufq_cwrite(&ctx->buf, buf + start, nread - start, &n);
- if(result)
- return result;
- }
+ /* Reset the trailing CRLF flag as there was more data */
+ smtp->trailing_crlf = FALSE;
}
- if(ctx->read_eos) {
- /* if we last matched a CRLF or if the data was empty, add ".\r\n"
- * to end the body. If we sent something and it did not end with "\r\n",
- * add "\r\n.\r\n" to end the body */
- const char *eob = SMTP_EOB;
- switch(ctx->n_eob) {
- case 2:
- /* seen a CRLF at the end, just add the remainder */
- eob = &SMTP_EOB[2];
- break;
- case 3:
- /* ended with '\r\n.', we should escpe the last '.' */
- eob = "." SMTP_EOB;
- break;
- default:
- break;
- }
- result = Curl_bufq_cwrite(&ctx->buf, eob, strlen(eob), &n);
- if(result)
- return result;
+ /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
+ if(SMTP_EOB_FIND_LEN == smtp->eob) {
+ /* Copy the replacement data to the target buffer */
+ memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent],
+ SMTP_EOB_REPL_LEN - eob_sent);
+ si += SMTP_EOB_REPL_LEN - eob_sent;
+ smtp->eob = 0;
+ eob_sent = 0;
}
+ else if(!smtp->eob)
+ scratch[si++] = data->req.upload_fromhere[i];
}
- *peos = FALSE;
- if(!Curl_bufq_is_empty(&ctx->buf)) {
- result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
+ if(smtp->eob - eob_sent) {
+ /* A substring matched before processing ended so output that now */
+ memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
+ si += smtp->eob - eob_sent;
}
- else
- *pnread = 0;
- if(ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
- /* no more data, read all, done. */
- ctx->eos = TRUE;
- }
- *peos = ctx->eos;
- DEBUGF(infof(data, "cr_eob_read(%zu) -> %d, %zd, %d",
- blen, result, *pnread, *peos));
- return result;
-}
+ /* Only use the new buffer if we replaced something */
+ if(si != nread) {
+ /* Upload from the new (replaced) buffer instead */
+ data->req.upload_fromhere = scratch;
-static curl_off_t cr_eob_total_length(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- /* this reader changes length depending on input */
- (void)data;
- (void)reader;
- return -1;
-}
+ /* Save the buffer so it can be freed later */
+ data->state.scratch = scratch;
-static const struct Curl_crtype cr_eob = {
- "cr-smtp-eob",
- cr_eob_init,
- cr_eob_read,
- cr_eob_close,
- Curl_creader_def_needs_rewind,
- cr_eob_total_length,
- Curl_creader_def_resume_from,
- Curl_creader_def_rewind,
- Curl_creader_def_unpause,
- Curl_creader_def_is_paused,
- Curl_creader_def_done,
- sizeof(struct cr_eob_ctx)
-};
-
-static CURLcode cr_eob_add(struct Curl_easy *data)
-{
- struct Curl_creader *reader = NULL;
- CURLcode result;
+ /* Free the old scratch buffer */
+ free(oldscratch);
- result = Curl_creader_create(&reader, data, &cr_eob,
- CURL_CR_CONTENT_ENCODE);
- if(!result)
- result = Curl_creader_add(data, reader);
+ /* Set the new amount too */
+ data->req.upload_present = si;
+ }
+ else
+ free(newscratch);
- if(result && reader)
- Curl_creader_free(data, reader);
- return result;
+ return CURLE_OK;
}
#endif /* CURL_DISABLE_SMTP */