mirror of
https://github.com/curl/curl.git
synced 2026-04-11 12:01:42 +08:00
lib: reorder protocol functions to avoid forward declarations (email)
For protocols: imap, pop3, smtp. Move protocol hander table to the end of sources, rearrange static functions is reverse dependency order as necessary. Closes #20275
This commit is contained in:
parent
07926b5982
commit
2ded1e3c6e
1041
lib/imap.c
1041
lib/imap.c
File diff suppressed because it is too large
Load Diff
729
lib/pop3.c
729
lib/pop3.c
@ -135,111 +135,6 @@ struct pop3_conn {
|
||||
BIT(tls_supported); /* StartTLS capability supported by server */
|
||||
};
|
||||
|
||||
/* Local API functions */
|
||||
static CURLcode pop3_regular_transfer(struct Curl_easy *data, bool *done);
|
||||
static CURLcode pop3_do(struct Curl_easy *data, bool *done);
|
||||
static CURLcode pop3_done(struct Curl_easy *data, CURLcode status,
|
||||
bool premature);
|
||||
static CURLcode pop3_connect(struct Curl_easy *data, bool *done);
|
||||
static CURLcode pop3_disconnect(struct Curl_easy *data,
|
||||
struct connectdata *conn, bool dead);
|
||||
static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done);
|
||||
static CURLcode pop3_pollset(struct Curl_easy *data,
|
||||
struct easy_pollset *ps);
|
||||
static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done);
|
||||
static CURLcode pop3_setup_connection(struct Curl_easy *data,
|
||||
struct connectdata *conn);
|
||||
static CURLcode pop3_parse_url_options(struct connectdata *conn);
|
||||
static CURLcode pop3_parse_url_path(struct Curl_easy *data);
|
||||
static CURLcode pop3_parse_custom_request(struct Curl_easy *data);
|
||||
static CURLcode pop3_perform_auth(struct Curl_easy *data, const char *mech,
|
||||
const struct bufref *initresp);
|
||||
static CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech,
|
||||
const struct bufref *resp);
|
||||
static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech);
|
||||
static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out);
|
||||
|
||||
/* This function scans the body after the end-of-body and writes everything
|
||||
* until the end is found */
|
||||
static CURLcode pop3_write(struct Curl_easy *data,
|
||||
const char *str, size_t nread, bool is_eos);
|
||||
|
||||
/*
|
||||
* POP3 protocol handler.
|
||||
*/
|
||||
|
||||
const struct Curl_handler Curl_handler_pop3 = {
|
||||
"pop3", /* scheme */
|
||||
pop3_setup_connection, /* setup_connection */
|
||||
pop3_do, /* do_it */
|
||||
pop3_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
pop3_connect, /* connect_it */
|
||||
pop3_multi_statemach, /* connecting */
|
||||
pop3_doing, /* doing */
|
||||
pop3_pollset, /* proto_pollset */
|
||||
pop3_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
pop3_disconnect, /* disconnect */
|
||||
pop3_write, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_POP3, /* defport */
|
||||
CURLPROTO_POP3, /* protocol */
|
||||
CURLPROTO_POP3, /* family */
|
||||
PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
|
||||
PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE | PROTOPT_CONN_REUSE
|
||||
};
|
||||
|
||||
#ifdef USE_SSL
|
||||
/*
|
||||
* POP3S protocol handler.
|
||||
*/
|
||||
|
||||
const struct Curl_handler Curl_handler_pop3s = {
|
||||
"pop3s", /* scheme */
|
||||
pop3_setup_connection, /* setup_connection */
|
||||
pop3_do, /* do_it */
|
||||
pop3_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
pop3_connect, /* connect_it */
|
||||
pop3_multi_statemach, /* connecting */
|
||||
pop3_doing, /* doing */
|
||||
pop3_pollset, /* proto_pollset */
|
||||
pop3_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
pop3_disconnect, /* disconnect */
|
||||
pop3_write, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_POP3S, /* defport */
|
||||
CURLPROTO_POP3S, /* protocol */
|
||||
CURLPROTO_POP3, /* family */
|
||||
PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS | PROTOPT_CONN_REUSE
|
||||
};
|
||||
#endif
|
||||
|
||||
/* SASL parameters for the pop3 protocol */
|
||||
static const struct SASLproto saslpop3 = {
|
||||
"pop", /* The service name */
|
||||
pop3_perform_auth, /* Send authentication command */
|
||||
pop3_continue_auth, /* Send authentication continuation */
|
||||
pop3_cancel_auth, /* Send authentication cancellation */
|
||||
pop3_get_message, /* Get SASL response message */
|
||||
255 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */
|
||||
'*', /* Code received when continuation is expected */
|
||||
'+', /* Code to receive upon authentication success */
|
||||
SASL_AUTH_DEFAULT, /* Default mechanisms */
|
||||
SASL_FLAG_BASE64 /* Configuration flags */
|
||||
};
|
||||
|
||||
struct pop3_cmd {
|
||||
const char *name;
|
||||
unsigned short nlen;
|
||||
@ -268,6 +163,105 @@ static const struct pop3_cmd pop3cmds[] = {
|
||||
{ "XTND", 4, TRUE, TRUE },
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_parse_url_options()
|
||||
*
|
||||
* Parse the URL login options.
|
||||
*/
|
||||
static CURLcode pop3_parse_url_options(struct connectdata *conn)
|
||||
{
|
||||
struct pop3_conn *pop3c = Curl_conn_meta_get(conn, CURL_META_POP3_CONN);
|
||||
CURLcode result = CURLE_OK;
|
||||
const char *ptr = conn->options;
|
||||
|
||||
if(!pop3c)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
while(!result && ptr && *ptr) {
|
||||
const char *key = ptr;
|
||||
const char *value;
|
||||
|
||||
while(*ptr && *ptr != '=')
|
||||
ptr++;
|
||||
|
||||
value = ptr + 1;
|
||||
|
||||
while(*ptr && *ptr != ';')
|
||||
ptr++;
|
||||
|
||||
if(curl_strnequal(key, "AUTH=", 5)) {
|
||||
result = Curl_sasl_parse_url_auth_option(&pop3c->sasl,
|
||||
value, ptr - value);
|
||||
|
||||
if(result && curl_strnequal(value, "+APOP", ptr - value)) {
|
||||
pop3c->preftype = POP3_TYPE_APOP;
|
||||
pop3c->sasl.prefmech = SASL_AUTH_NONE;
|
||||
result = CURLE_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
|
||||
if(*ptr == ';')
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if(pop3c->preftype != POP3_TYPE_APOP)
|
||||
switch(pop3c->sasl.prefmech) {
|
||||
case SASL_AUTH_NONE:
|
||||
pop3c->preftype = POP3_TYPE_NONE;
|
||||
break;
|
||||
case SASL_AUTH_DEFAULT:
|
||||
pop3c->preftype = POP3_TYPE_ANY;
|
||||
break;
|
||||
default:
|
||||
pop3c->preftype = POP3_TYPE_SASL;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_parse_url_path()
|
||||
*
|
||||
* Parse the URL path into separate path components.
|
||||
*/
|
||||
static CURLcode pop3_parse_url_path(struct Curl_easy *data)
|
||||
{
|
||||
/* The POP3 struct is already initialised in pop3_connect() */
|
||||
struct POP3 *pop3 = Curl_meta_get(data, CURL_META_POP3_EASY);
|
||||
const char *path = &data->state.up.path[1]; /* skip leading path */
|
||||
|
||||
if(!pop3)
|
||||
return CURLE_FAILED_INIT;
|
||||
/* URL decode the path for the message ID */
|
||||
return Curl_urldecode(path, 0, &pop3->id, NULL, REJECT_CTRL);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_parse_custom_request()
|
||||
*
|
||||
* Parse the custom request.
|
||||
*/
|
||||
static CURLcode pop3_parse_custom_request(struct Curl_easy *data)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct POP3 *pop3 = Curl_meta_get(data, CURL_META_POP3_EASY);
|
||||
const char *custom = data->set.str[STRING_CUSTOMREQUEST];
|
||||
|
||||
if(!pop3)
|
||||
return CURLE_FAILED_INIT;
|
||||
/* URL decode the custom request */
|
||||
if(custom)
|
||||
result = Curl_urldecode(custom, 0, &pop3->custom, NULL, REJECT_CTRL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return iff a command is defined as "multi-line" (RFC 1939),
|
||||
* has a response terminated by a last line with a '.'.
|
||||
*/
|
||||
@ -1070,6 +1064,146 @@ static CURLcode pop3_state_pass_resp(struct Curl_easy *data, int pop3code,
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_write()
|
||||
*
|
||||
* This function scans the body after the end-of-body and writes everything
|
||||
* until the end is found.
|
||||
*/
|
||||
static CURLcode pop3_write(struct Curl_easy *data, const char *str,
|
||||
size_t nread, bool is_eos)
|
||||
{
|
||||
/* This code could be made into a special function in the handler struct */
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SingleRequest *k = &data->req;
|
||||
struct connectdata *conn = data->conn;
|
||||
struct pop3_conn *pop3c = Curl_conn_meta_get(conn, CURL_META_POP3_CONN);
|
||||
bool strip_dot = FALSE;
|
||||
size_t last = 0;
|
||||
size_t i;
|
||||
(void)is_eos;
|
||||
|
||||
if(!pop3c)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
/* Search through the buffer looking for the end-of-body marker which is
|
||||
5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
|
||||
the eob so the server will have prefixed it with an extra dot which we
|
||||
need to strip out. Additionally the marker could of course be spread out
|
||||
over 5 different data chunks. */
|
||||
for(i = 0; i < nread; i++) {
|
||||
size_t prev = pop3c->eob;
|
||||
|
||||
switch(str[i]) {
|
||||
case 0x0d:
|
||||
if(pop3c->eob == 0) {
|
||||
pop3c->eob++;
|
||||
|
||||
if(i) {
|
||||
/* Write out the body part that did not match */
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
|
||||
i - last);
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
else if(pop3c->eob == 3)
|
||||
pop3c->eob++;
|
||||
else
|
||||
/* If the character match was not at position 0 or 3 then restart the
|
||||
pattern matching */
|
||||
pop3c->eob = 1;
|
||||
break;
|
||||
|
||||
case 0x0a:
|
||||
if(pop3c->eob == 1 || pop3c->eob == 4)
|
||||
pop3c->eob++;
|
||||
else
|
||||
/* If the character match was not at position 1 or 4 then start the
|
||||
search again */
|
||||
pop3c->eob = 0;
|
||||
break;
|
||||
|
||||
case 0x2e:
|
||||
if(pop3c->eob == 2)
|
||||
pop3c->eob++;
|
||||
else if(pop3c->eob == 3) {
|
||||
/* We have an extra dot after the CRLF which we need to strip off */
|
||||
strip_dot = TRUE;
|
||||
pop3c->eob = 0;
|
||||
}
|
||||
else
|
||||
/* If the character match was not at position 2 then start the search
|
||||
again */
|
||||
pop3c->eob = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
pop3c->eob = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Did we have a partial match which has subsequently failed? */
|
||||
if(prev && prev >= pop3c->eob) {
|
||||
/* Strip can only be non-zero for the first mismatch after CRLF and
|
||||
then both prev and strip are equal and nothing will be output below */
|
||||
while(prev && pop3c->strip) {
|
||||
prev--;
|
||||
pop3c->strip--;
|
||||
}
|
||||
|
||||
if(prev) {
|
||||
/* If the partial match was the CRLF and dot then only write the CRLF
|
||||
as the server would have inserted the dot */
|
||||
if(strip_dot && prev - 1 > 0) {
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, POP3_EOB,
|
||||
prev - 1);
|
||||
}
|
||||
else if(!strip_dot) {
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, POP3_EOB,
|
||||
prev);
|
||||
}
|
||||
else {
|
||||
result = CURLE_OK;
|
||||
}
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
last = i;
|
||||
strip_dot = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(pop3c->eob == POP3_EOB_LEN) {
|
||||
/* We have a full match so the transfer is done, however we must transfer
|
||||
the CRLF at the start of the EOB as this is considered to be part of the
|
||||
message as per RFC-1939, sect. 3 */
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, POP3_EOB, 2);
|
||||
|
||||
k->keepon &= ~KEEP_RECV;
|
||||
pop3c->eob = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if(pop3c->eob)
|
||||
/* While EOB is matching nothing should be output */
|
||||
return CURLE_OK;
|
||||
|
||||
if(nread - last) {
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
|
||||
nread - last);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* For command responses */
|
||||
static CURLcode pop3_state_command_resp(struct Curl_easy *data,
|
||||
int pop3code,
|
||||
@ -1264,6 +1398,20 @@ static CURLcode pop3_pollset(struct Curl_easy *data,
|
||||
return pop3c ? Curl_pp_pollset(data, &pop3c->pp, ps) : CURLE_OK;
|
||||
}
|
||||
|
||||
/* SASL parameters for the pop3 protocol */
|
||||
static const struct SASLproto saslpop3 = {
|
||||
"pop", /* The service name */
|
||||
pop3_perform_auth, /* Send authentication command */
|
||||
pop3_continue_auth, /* Send authentication continuation */
|
||||
pop3_cancel_auth, /* Send authentication cancellation */
|
||||
pop3_get_message, /* Get SASL response message */
|
||||
255 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */
|
||||
'*', /* Code received when continuation is expected */
|
||||
'+', /* Code to receive upon authentication success */
|
||||
SASL_AUTH_DEFAULT, /* Default mechanisms */
|
||||
SASL_FLAG_BASE64 /* Configuration flags */
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_connect()
|
||||
@ -1382,6 +1530,46 @@ static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Call this when the DO phase has completed */
|
||||
static CURLcode pop3_dophase_done(struct Curl_easy *data, bool connected)
|
||||
{
|
||||
(void)data;
|
||||
(void)connected;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_regular_transfer()
|
||||
*
|
||||
* The input argument is already checked for validity.
|
||||
*
|
||||
* Performs all commands done before a regular transfer between a local and a
|
||||
* remote host.
|
||||
*/
|
||||
static CURLcode pop3_regular_transfer(struct Curl_easy *data,
|
||||
bool *dophase_done)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
bool connected = FALSE;
|
||||
|
||||
/* Make sure size is unknown at this point */
|
||||
data->req.size = -1;
|
||||
|
||||
/* Set the progress data */
|
||||
Curl_pgrsReset(data);
|
||||
|
||||
/* Carry out the perform */
|
||||
result = pop3_perform(data, &connected, dophase_done);
|
||||
|
||||
/* Perform post DO phase operations if necessary */
|
||||
if(!result && *dophase_done)
|
||||
result = pop3_dophase_done(data, connected);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_do()
|
||||
@ -1446,15 +1634,6 @@ static CURLcode pop3_disconnect(struct Curl_easy *data,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Call this when the DO phase has completed */
|
||||
static CURLcode pop3_dophase_done(struct Curl_easy *data, bool connected)
|
||||
{
|
||||
(void)data;
|
||||
(void)connected;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Called from multi.c while DOing */
|
||||
static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done)
|
||||
{
|
||||
@ -1471,37 +1650,6 @@ static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done)
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_regular_transfer()
|
||||
*
|
||||
* The input argument is already checked for validity.
|
||||
*
|
||||
* Performs all commands done before a regular transfer between a local and a
|
||||
* remote host.
|
||||
*/
|
||||
static CURLcode pop3_regular_transfer(struct Curl_easy *data,
|
||||
bool *dophase_done)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
bool connected = FALSE;
|
||||
|
||||
/* Make sure size is unknown at this point */
|
||||
data->req.size = -1;
|
||||
|
||||
/* Set the progress data */
|
||||
Curl_pgrsReset(data);
|
||||
|
||||
/* Carry out the perform */
|
||||
result = pop3_perform(data, &connected, dophase_done);
|
||||
|
||||
/* Perform post DO phase operations if necessary */
|
||||
if(!result && *dophase_done)
|
||||
result = pop3_dophase_done(data, connected);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void pop3_easy_dtor(void *key, size_t klen, void *entry)
|
||||
{
|
||||
struct POP3 *pop3 = entry;
|
||||
@ -1542,243 +1690,64 @@ static CURLcode pop3_setup_connection(struct Curl_easy *data,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_parse_url_options()
|
||||
*
|
||||
* Parse the URL login options.
|
||||
/*
|
||||
* POP3 protocol handler.
|
||||
*/
|
||||
static CURLcode pop3_parse_url_options(struct connectdata *conn)
|
||||
{
|
||||
struct pop3_conn *pop3c = Curl_conn_meta_get(conn, CURL_META_POP3_CONN);
|
||||
CURLcode result = CURLE_OK;
|
||||
const char *ptr = conn->options;
|
||||
const struct Curl_handler Curl_handler_pop3 = {
|
||||
"pop3", /* scheme */
|
||||
pop3_setup_connection, /* setup_connection */
|
||||
pop3_do, /* do_it */
|
||||
pop3_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
pop3_connect, /* connect_it */
|
||||
pop3_multi_statemach, /* connecting */
|
||||
pop3_doing, /* doing */
|
||||
pop3_pollset, /* proto_pollset */
|
||||
pop3_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
pop3_disconnect, /* disconnect */
|
||||
pop3_write, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_POP3, /* defport */
|
||||
CURLPROTO_POP3, /* protocol */
|
||||
CURLPROTO_POP3, /* family */
|
||||
PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
|
||||
PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE | PROTOPT_CONN_REUSE
|
||||
};
|
||||
|
||||
if(!pop3c)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
while(!result && ptr && *ptr) {
|
||||
const char *key = ptr;
|
||||
const char *value;
|
||||
|
||||
while(*ptr && *ptr != '=')
|
||||
ptr++;
|
||||
|
||||
value = ptr + 1;
|
||||
|
||||
while(*ptr && *ptr != ';')
|
||||
ptr++;
|
||||
|
||||
if(curl_strnequal(key, "AUTH=", 5)) {
|
||||
result = Curl_sasl_parse_url_auth_option(&pop3c->sasl,
|
||||
value, ptr - value);
|
||||
|
||||
if(result && curl_strnequal(value, "+APOP", ptr - value)) {
|
||||
pop3c->preftype = POP3_TYPE_APOP;
|
||||
pop3c->sasl.prefmech = SASL_AUTH_NONE;
|
||||
result = CURLE_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
|
||||
if(*ptr == ';')
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if(pop3c->preftype != POP3_TYPE_APOP)
|
||||
switch(pop3c->sasl.prefmech) {
|
||||
case SASL_AUTH_NONE:
|
||||
pop3c->preftype = POP3_TYPE_NONE;
|
||||
break;
|
||||
case SASL_AUTH_DEFAULT:
|
||||
pop3c->preftype = POP3_TYPE_ANY;
|
||||
break;
|
||||
default:
|
||||
pop3c->preftype = POP3_TYPE_SASL;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_parse_url_path()
|
||||
*
|
||||
* Parse the URL path into separate path components.
|
||||
#ifdef USE_SSL
|
||||
/*
|
||||
* POP3S protocol handler.
|
||||
*/
|
||||
static CURLcode pop3_parse_url_path(struct Curl_easy *data)
|
||||
{
|
||||
/* The POP3 struct is already initialised in pop3_connect() */
|
||||
struct POP3 *pop3 = Curl_meta_get(data, CURL_META_POP3_EASY);
|
||||
const char *path = &data->state.up.path[1]; /* skip leading path */
|
||||
|
||||
if(!pop3)
|
||||
return CURLE_FAILED_INIT;
|
||||
/* URL decode the path for the message ID */
|
||||
return Curl_urldecode(path, 0, &pop3->id, NULL, REJECT_CTRL);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_parse_custom_request()
|
||||
*
|
||||
* Parse the custom request.
|
||||
*/
|
||||
static CURLcode pop3_parse_custom_request(struct Curl_easy *data)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct POP3 *pop3 = Curl_meta_get(data, CURL_META_POP3_EASY);
|
||||
const char *custom = data->set.str[STRING_CUSTOMREQUEST];
|
||||
|
||||
if(!pop3)
|
||||
return CURLE_FAILED_INIT;
|
||||
/* URL decode the custom request */
|
||||
if(custom)
|
||||
result = Curl_urldecode(custom, 0, &pop3->custom, NULL, REJECT_CTRL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* pop3_write()
|
||||
*
|
||||
* This function scans the body after the end-of-body and writes everything
|
||||
* until the end is found.
|
||||
*/
|
||||
static CURLcode pop3_write(struct Curl_easy *data, const char *str,
|
||||
size_t nread, bool is_eos)
|
||||
{
|
||||
/* This code could be made into a special function in the handler struct */
|
||||
CURLcode result = CURLE_OK;
|
||||
struct SingleRequest *k = &data->req;
|
||||
struct connectdata *conn = data->conn;
|
||||
struct pop3_conn *pop3c = Curl_conn_meta_get(conn, CURL_META_POP3_CONN);
|
||||
bool strip_dot = FALSE;
|
||||
size_t last = 0;
|
||||
size_t i;
|
||||
(void)is_eos;
|
||||
|
||||
if(!pop3c)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
/* Search through the buffer looking for the end-of-body marker which is
|
||||
5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
|
||||
the eob so the server will have prefixed it with an extra dot which we
|
||||
need to strip out. Additionally the marker could of course be spread out
|
||||
over 5 different data chunks. */
|
||||
for(i = 0; i < nread; i++) {
|
||||
size_t prev = pop3c->eob;
|
||||
|
||||
switch(str[i]) {
|
||||
case 0x0d:
|
||||
if(pop3c->eob == 0) {
|
||||
pop3c->eob++;
|
||||
|
||||
if(i) {
|
||||
/* Write out the body part that did not match */
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
|
||||
i - last);
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
else if(pop3c->eob == 3)
|
||||
pop3c->eob++;
|
||||
else
|
||||
/* If the character match was not at position 0 or 3 then restart the
|
||||
pattern matching */
|
||||
pop3c->eob = 1;
|
||||
break;
|
||||
|
||||
case 0x0a:
|
||||
if(pop3c->eob == 1 || pop3c->eob == 4)
|
||||
pop3c->eob++;
|
||||
else
|
||||
/* If the character match was not at position 1 or 4 then start the
|
||||
search again */
|
||||
pop3c->eob = 0;
|
||||
break;
|
||||
|
||||
case 0x2e:
|
||||
if(pop3c->eob == 2)
|
||||
pop3c->eob++;
|
||||
else if(pop3c->eob == 3) {
|
||||
/* We have an extra dot after the CRLF which we need to strip off */
|
||||
strip_dot = TRUE;
|
||||
pop3c->eob = 0;
|
||||
}
|
||||
else
|
||||
/* If the character match was not at position 2 then start the search
|
||||
again */
|
||||
pop3c->eob = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
pop3c->eob = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Did we have a partial match which has subsequently failed? */
|
||||
if(prev && prev >= pop3c->eob) {
|
||||
/* Strip can only be non-zero for the first mismatch after CRLF and
|
||||
then both prev and strip are equal and nothing will be output below */
|
||||
while(prev && pop3c->strip) {
|
||||
prev--;
|
||||
pop3c->strip--;
|
||||
}
|
||||
|
||||
if(prev) {
|
||||
/* If the partial match was the CRLF and dot then only write the CRLF
|
||||
as the server would have inserted the dot */
|
||||
if(strip_dot && prev - 1 > 0) {
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, POP3_EOB,
|
||||
prev - 1);
|
||||
}
|
||||
else if(!strip_dot) {
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, POP3_EOB,
|
||||
prev);
|
||||
}
|
||||
else {
|
||||
result = CURLE_OK;
|
||||
}
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
last = i;
|
||||
strip_dot = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(pop3c->eob == POP3_EOB_LEN) {
|
||||
/* We have a full match so the transfer is done, however we must transfer
|
||||
the CRLF at the start of the EOB as this is considered to be part of the
|
||||
message as per RFC-1939, sect. 3 */
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, POP3_EOB, 2);
|
||||
|
||||
k->keepon &= ~KEEP_RECV;
|
||||
pop3c->eob = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if(pop3c->eob)
|
||||
/* While EOB is matching nothing should be output */
|
||||
return CURLE_OK;
|
||||
|
||||
if(nread - last) {
|
||||
result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
|
||||
nread - last);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
const struct Curl_handler Curl_handler_pop3s = {
|
||||
"pop3s", /* scheme */
|
||||
pop3_setup_connection, /* setup_connection */
|
||||
pop3_do, /* do_it */
|
||||
pop3_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
pop3_connect, /* connect_it */
|
||||
pop3_multi_statemach, /* connecting */
|
||||
pop3_doing, /* doing */
|
||||
pop3_pollset, /* proto_pollset */
|
||||
pop3_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
pop3_disconnect, /* disconnect */
|
||||
pop3_write, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_POP3S, /* defport */
|
||||
CURLPROTO_POP3S, /* protocol */
|
||||
CURLPROTO_POP3, /* family */
|
||||
PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS | PROTOPT_CONN_REUSE
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* CURL_DISABLE_POP3 */
|
||||
|
||||
924
lib/smtp.c
924
lib/smtp.c
@ -136,116 +136,344 @@ struct SMTP {
|
||||
BIT(trailing_crlf); /* Specifies if the trailing CRLF is present */
|
||||
};
|
||||
|
||||
/* Local API functions */
|
||||
static CURLcode smtp_regular_transfer(struct Curl_easy *data,
|
||||
struct smtp_conn *smtpc,
|
||||
struct SMTP *smtp,
|
||||
bool *done);
|
||||
static CURLcode smtp_do(struct Curl_easy *data, bool *done);
|
||||
static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
|
||||
bool premature);
|
||||
static CURLcode smtp_connect(struct Curl_easy *data, bool *done);
|
||||
static CURLcode smtp_disconnect(struct Curl_easy *data,
|
||||
struct connectdata *conn, bool dead);
|
||||
static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done);
|
||||
static CURLcode smtp_pollset(struct Curl_easy *data,
|
||||
struct easy_pollset *ps);
|
||||
static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done);
|
||||
static CURLcode smtp_setup_connection(struct Curl_easy *data,
|
||||
struct connectdata *conn);
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_parse_url_options()
|
||||
*
|
||||
* Parse the URL login options.
|
||||
*/
|
||||
static CURLcode smtp_parse_url_options(struct connectdata *conn,
|
||||
struct smtp_conn *smtpc);
|
||||
struct smtp_conn *smtpc)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
const char *ptr = conn->options;
|
||||
|
||||
while(!result && ptr && *ptr) {
|
||||
const char *key = ptr;
|
||||
const char *value;
|
||||
|
||||
while(*ptr && *ptr != '=')
|
||||
ptr++;
|
||||
|
||||
value = ptr + 1;
|
||||
|
||||
while(*ptr && *ptr != ';')
|
||||
ptr++;
|
||||
|
||||
if(curl_strnequal(key, "AUTH=", 5))
|
||||
result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
|
||||
value, ptr - value);
|
||||
else
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
|
||||
if(*ptr == ';')
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_parse_url_path()
|
||||
*
|
||||
* Parse the URL path into separate path components.
|
||||
*/
|
||||
static CURLcode smtp_parse_url_path(struct Curl_easy *data,
|
||||
struct smtp_conn *smtpc);
|
||||
struct smtp_conn *smtpc)
|
||||
{
|
||||
/* The SMTP struct is already initialised in smtp_connect() */
|
||||
const char *path = &data->state.up.path[1]; /* skip leading path */
|
||||
char localhost[HOSTNAME_MAX + 1];
|
||||
|
||||
/* Calculate the path if necessary */
|
||||
if(!*path) {
|
||||
if(!Curl_gethostname(localhost, sizeof(localhost)))
|
||||
path = localhost;
|
||||
else
|
||||
path = "localhost";
|
||||
}
|
||||
|
||||
/* URL decode the path and use it as the domain in our EHLO */
|
||||
return Curl_urldecode(path, 0, &smtpc->domain, NULL, REJECT_CTRL);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_parse_custom_request()
|
||||
*
|
||||
* Parse the custom request.
|
||||
*/
|
||||
static CURLcode smtp_parse_custom_request(struct Curl_easy *data,
|
||||
struct SMTP *smtp);
|
||||
static CURLcode smtp_parse_address(const char *fqma,
|
||||
char **address, struct hostname *host,
|
||||
const char **suffix);
|
||||
static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech,
|
||||
const struct bufref *initresp);
|
||||
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);
|
||||
struct SMTP *smtp)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
const char *custom = data->set.str[STRING_CUSTOMREQUEST];
|
||||
|
||||
/*
|
||||
* SMTP protocol handler.
|
||||
/* URL decode the custom request */
|
||||
if(custom)
|
||||
result = Curl_urldecode(custom, 0, &smtp->custom, NULL, REJECT_CTRL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* 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
|
||||
* necessary.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* conn [in] - The connection handle.
|
||||
* fqma [in] - The fully qualified mailbox address (which may or
|
||||
* may not contain UTF-8 characters).
|
||||
* 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.
|
||||
* Curl_free_idnconverted_hostname() must be called
|
||||
* once the caller has finished with the structure.
|
||||
*
|
||||
* Returns CURLE_OK on success.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* Should a UTF-8 hostname 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.
|
||||
*/
|
||||
static CURLcode smtp_parse_address(const char *fqma, char **address,
|
||||
struct hostname *host, const char **suffix)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t length;
|
||||
char *addressend;
|
||||
|
||||
const struct Curl_handler Curl_handler_smtp = {
|
||||
"smtp", /* scheme */
|
||||
smtp_setup_connection, /* setup_connection */
|
||||
smtp_do, /* do_it */
|
||||
smtp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
smtp_connect, /* connect_it */
|
||||
smtp_multi_statemach, /* connecting */
|
||||
smtp_doing, /* doing */
|
||||
smtp_pollset, /* proto_pollset */
|
||||
smtp_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
smtp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SMTP, /* defport */
|
||||
CURLPROTO_SMTP, /* protocol */
|
||||
CURLPROTO_SMTP, /* family */
|
||||
PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
|
||||
PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE | PROTOPT_CONN_REUSE
|
||||
/* Duplicate the fully qualified email address so we can manipulate it,
|
||||
ensuring it does not contain the delimiters if specified */
|
||||
char *dup = curlx_strdup(fqma[0] == '<' ? fqma + 1 : fqma);
|
||||
if(!dup)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(fqma[0] != '<') {
|
||||
length = strlen(dup);
|
||||
if(length) {
|
||||
if(dup[length - 1] == '>')
|
||||
dup[length - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else {
|
||||
addressend = strrchr(dup, '>');
|
||||
if(addressend) {
|
||||
*addressend = '\0';
|
||||
*suffix = addressend + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract the hostname 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 */
|
||||
(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
|
||||
our preference) */
|
||||
}
|
||||
|
||||
/* Extract the local address from the mailbox */
|
||||
*address = dup;
|
||||
|
||||
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(processed_eos); /* we read and processed an EOS */
|
||||
BIT(eos); /* we have returned an EOS */
|
||||
};
|
||||
|
||||
#ifdef USE_SSL
|
||||
/*
|
||||
* SMTPS protocol handler.
|
||||
*/
|
||||
static CURLcode cr_eob_init(struct Curl_easy *data,
|
||||
struct Curl_creader *reader)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
const struct Curl_handler Curl_handler_smtps = {
|
||||
"smtps", /* scheme */
|
||||
smtp_setup_connection, /* setup_connection */
|
||||
smtp_do, /* do_it */
|
||||
smtp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
smtp_connect, /* connect_it */
|
||||
smtp_multi_statemach, /* connecting */
|
||||
smtp_doing, /* doing */
|
||||
smtp_pollset, /* proto_pollset */
|
||||
smtp_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
smtp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SMTPS, /* defport */
|
||||
CURLPROTO_SMTPS, /* protocol */
|
||||
CURLPROTO_SMTP, /* family */
|
||||
PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS | PROTOPT_CONN_REUSE
|
||||
};
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
||||
/* SASL parameters for the smtp protocol */
|
||||
static const struct SASLproto saslsmtp = {
|
||||
"smtp", /* The service name */
|
||||
smtp_perform_auth, /* Send authentication command */
|
||||
smtp_continue_auth, /* Send authentication continuation */
|
||||
smtp_cancel_auth, /* Cancel authentication */
|
||||
smtp_get_message, /* Get SASL response message */
|
||||
512 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */
|
||||
334, /* Code received when continuation is expected */
|
||||
235, /* Code to receive upon authentication success */
|
||||
SASL_AUTH_DEFAULT, /* Default mechanisms */
|
||||
SASL_FLAG_BASE64 /* Configuration flags */
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
CURL_TRC_SMTP(data, "cr_eob_read, next_read(len=%zu) -> %d, %zu eos=%d",
|
||||
blen, result, nread, eos);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
if(buf[i] != SMTP_EOB[ctx->n_eob])
|
||||
ctx->n_eob = 0;
|
||||
|
||||
if(buf[i] == SMTP_EOB[ctx->n_eob]) {
|
||||
/* matching another char of the EOB */
|
||||
++ctx->n_eob;
|
||||
}
|
||||
}
|
||||
|
||||
/* add any remainder to buf */
|
||||
if(start < nread) {
|
||||
result = Curl_bufq_cwrite(&ctx->buf, buf + start, nread - start, &n);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*peos = FALSE;
|
||||
|
||||
if(ctx->read_eos && !ctx->processed_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;
|
||||
CURL_TRC_SMTP(data, "auto-ending mail body with '\\r\\n.\\r\\n'");
|
||||
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 escape the last '.' */
|
||||
eob = "." SMTP_EOB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
result = Curl_bufq_cwrite(&ctx->buf, eob, strlen(eob), &n);
|
||||
if(result)
|
||||
return result;
|
||||
ctx->processed_eos = TRUE;
|
||||
}
|
||||
|
||||
if(!Curl_bufq_is_empty(&ctx->buf)) {
|
||||
result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
|
||||
}
|
||||
else
|
||||
*pnread = 0;
|
||||
|
||||
if(ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
|
||||
/* no more data, read all, done. */
|
||||
CURL_TRC_SMTP(data, "mail body complete, returning EOS");
|
||||
ctx->eos = TRUE;
|
||||
}
|
||||
*peos = ctx->eos;
|
||||
DEBUGF(infof(data, "cr_eob_read(%zu) -> %d, %zd, %d",
|
||||
blen, result, *pnread, *peos));
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_cntrl,
|
||||
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;
|
||||
|
||||
result = Curl_creader_create(&reader, data, &cr_eob, CURL_CR_CONTENT_ENCODE);
|
||||
if(!result)
|
||||
result = Curl_creader_add(data, reader);
|
||||
|
||||
if(result && reader)
|
||||
Curl_creader_free(data, reader);
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_endofresp()
|
||||
@ -1413,6 +1641,20 @@ static CURLcode smtp_pollset(struct Curl_easy *data,
|
||||
return smtpc ? Curl_pp_pollset(data, &smtpc->pp, ps) : CURLE_OK;
|
||||
}
|
||||
|
||||
/* SASL parameters for the smtp protocol */
|
||||
static const struct SASLproto saslsmtp = {
|
||||
"smtp", /* The service name */
|
||||
smtp_perform_auth, /* Send authentication command */
|
||||
smtp_continue_auth, /* Send authentication continuation */
|
||||
smtp_cancel_auth, /* Cancel authentication */
|
||||
smtp_get_message, /* Get SASL response message */
|
||||
512 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */
|
||||
334, /* Code received when continuation is expected */
|
||||
235, /* Code to receive upon authentication success */
|
||||
SASL_AUTH_DEFAULT, /* Default mechanisms */
|
||||
SASL_FLAG_BASE64 /* Configuration flags */
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_connect()
|
||||
@ -1568,6 +1810,55 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Call this when the DO phase has completed */
|
||||
static CURLcode smtp_dophase_done(struct Curl_easy *data,
|
||||
struct SMTP *smtp,
|
||||
bool connected)
|
||||
{
|
||||
(void)connected;
|
||||
|
||||
if(smtp->transfer != PPTRANSFER_BODY)
|
||||
/* no data to transfer */
|
||||
Curl_xfer_setup_nop(data);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_regular_transfer()
|
||||
*
|
||||
* The input argument is already checked for validity.
|
||||
*
|
||||
* Performs all commands done before a regular transfer between a local and a
|
||||
* remote host.
|
||||
*/
|
||||
static CURLcode smtp_regular_transfer(struct Curl_easy *data,
|
||||
struct smtp_conn *smtpc,
|
||||
struct SMTP *smtp,
|
||||
bool *dophase_done)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
bool connected = FALSE;
|
||||
|
||||
/* Make sure size is unknown at this point */
|
||||
data->req.size = -1;
|
||||
|
||||
/* Set the progress data */
|
||||
Curl_pgrsReset(data);
|
||||
|
||||
/* Carry out the perform */
|
||||
result = smtp_perform(data, smtpc, smtp, &connected, dophase_done);
|
||||
|
||||
/* Perform post DO phase operations if necessary */
|
||||
if(!result && *dophase_done)
|
||||
result = smtp_dophase_done(data, smtp, connected);
|
||||
|
||||
CURL_TRC_SMTP(data, "smtp_regular_transfer() -> %d, done=%d",
|
||||
result, *dophase_done);
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_do()
|
||||
@ -1631,20 +1922,6 @@ static CURLcode smtp_disconnect(struct Curl_easy *data,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Call this when the DO phase has completed */
|
||||
static CURLcode smtp_dophase_done(struct Curl_easy *data,
|
||||
struct SMTP *smtp,
|
||||
bool connected)
|
||||
{
|
||||
(void)connected;
|
||||
|
||||
if(smtp->transfer != PPTRANSFER_BODY)
|
||||
/* no data to transfer */
|
||||
Curl_xfer_setup_nop(data);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Called from multi.c while DOing */
|
||||
static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done)
|
||||
{
|
||||
@ -1666,41 +1943,6 @@ static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done)
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_regular_transfer()
|
||||
*
|
||||
* The input argument is already checked for validity.
|
||||
*
|
||||
* Performs all commands done before a regular transfer between a local and a
|
||||
* remote host.
|
||||
*/
|
||||
static CURLcode smtp_regular_transfer(struct Curl_easy *data,
|
||||
struct smtp_conn *smtpc,
|
||||
struct SMTP *smtp,
|
||||
bool *dophase_done)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
bool connected = FALSE;
|
||||
|
||||
/* Make sure size is unknown at this point */
|
||||
data->req.size = -1;
|
||||
|
||||
/* Set the progress data */
|
||||
Curl_pgrsReset(data);
|
||||
|
||||
/* Carry out the perform */
|
||||
result = smtp_perform(data, smtpc, smtp, &connected, dophase_done);
|
||||
|
||||
/* Perform post DO phase operations if necessary */
|
||||
if(!result && *dophase_done)
|
||||
result = smtp_dophase_done(data, smtp, connected);
|
||||
|
||||
CURL_TRC_SMTP(data, "smtp_regular_transfer() -> %d, done=%d",
|
||||
result, *dophase_done);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void smtp_easy_dtor(void *key, size_t klen, void *entry)
|
||||
{
|
||||
struct SMTP *smtp = entry;
|
||||
@ -1743,342 +1985,64 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_parse_url_options()
|
||||
*
|
||||
* Parse the URL login options.
|
||||
/*
|
||||
* SMTP protocol handler.
|
||||
*/
|
||||
static CURLcode smtp_parse_url_options(struct connectdata *conn,
|
||||
struct smtp_conn *smtpc)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
const char *ptr = conn->options;
|
||||
|
||||
while(!result && ptr && *ptr) {
|
||||
const char *key = ptr;
|
||||
const char *value;
|
||||
|
||||
while(*ptr && *ptr != '=')
|
||||
ptr++;
|
||||
|
||||
value = ptr + 1;
|
||||
|
||||
while(*ptr && *ptr != ';')
|
||||
ptr++;
|
||||
|
||||
if(curl_strnequal(key, "AUTH=", 5))
|
||||
result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
|
||||
value, ptr - value);
|
||||
else
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
|
||||
if(*ptr == ';')
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_parse_url_path()
|
||||
*
|
||||
* Parse the URL path into separate path components.
|
||||
*/
|
||||
static CURLcode smtp_parse_url_path(struct Curl_easy *data,
|
||||
struct smtp_conn *smtpc)
|
||||
{
|
||||
/* The SMTP struct is already initialised in smtp_connect() */
|
||||
const char *path = &data->state.up.path[1]; /* skip leading path */
|
||||
char localhost[HOSTNAME_MAX + 1];
|
||||
|
||||
/* Calculate the path if necessary */
|
||||
if(!*path) {
|
||||
if(!Curl_gethostname(localhost, sizeof(localhost)))
|
||||
path = localhost;
|
||||
else
|
||||
path = "localhost";
|
||||
}
|
||||
|
||||
/* URL decode the path and use it as the domain in our EHLO */
|
||||
return Curl_urldecode(path, 0, &smtpc->domain, NULL, REJECT_CTRL);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* smtp_parse_custom_request()
|
||||
*
|
||||
* Parse the custom request.
|
||||
*/
|
||||
static CURLcode smtp_parse_custom_request(struct Curl_easy *data,
|
||||
struct SMTP *smtp)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
const char *custom = data->set.str[STRING_CUSTOMREQUEST];
|
||||
|
||||
/* URL decode the custom request */
|
||||
if(custom)
|
||||
result = Curl_urldecode(custom, 0, &smtp->custom, NULL, REJECT_CTRL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* 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
|
||||
* necessary.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* conn [in] - The connection handle.
|
||||
* fqma [in] - The fully qualified mailbox address (which may or
|
||||
* may not contain UTF-8 characters).
|
||||
* 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.
|
||||
* Curl_free_idnconverted_hostname() must be called
|
||||
* once the caller has finished with the structure.
|
||||
*
|
||||
* Returns CURLE_OK on success.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* Should a UTF-8 hostname 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.
|
||||
*/
|
||||
static CURLcode smtp_parse_address(const char *fqma, char **address,
|
||||
struct hostname *host, const char **suffix)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t length;
|
||||
char *addressend;
|
||||
|
||||
/* Duplicate the fully qualified email address so we can manipulate it,
|
||||
ensuring it does not contain the delimiters if specified */
|
||||
char *dup = curlx_strdup(fqma[0] == '<' ? fqma + 1 : fqma);
|
||||
if(!dup)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(fqma[0] != '<') {
|
||||
length = strlen(dup);
|
||||
if(length) {
|
||||
if(dup[length - 1] == '>')
|
||||
dup[length - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else {
|
||||
addressend = strrchr(dup, '>');
|
||||
if(addressend) {
|
||||
*addressend = '\0';
|
||||
*suffix = addressend + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract the hostname 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 */
|
||||
(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
|
||||
our preference) */
|
||||
}
|
||||
|
||||
/* Extract the local address from the mailbox */
|
||||
*address = dup;
|
||||
|
||||
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(processed_eos); /* we read and processed an EOS */
|
||||
BIT(eos); /* we have returned an EOS */
|
||||
const struct Curl_handler Curl_handler_smtp = {
|
||||
"smtp", /* scheme */
|
||||
smtp_setup_connection, /* setup_connection */
|
||||
smtp_do, /* do_it */
|
||||
smtp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
smtp_connect, /* connect_it */
|
||||
smtp_multi_statemach, /* connecting */
|
||||
smtp_doing, /* doing */
|
||||
smtp_pollset, /* proto_pollset */
|
||||
smtp_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
smtp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SMTP, /* defport */
|
||||
CURLPROTO_SMTP, /* protocol */
|
||||
CURLPROTO_SMTP, /* family */
|
||||
PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
|
||||
PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE | PROTOPT_CONN_REUSE
|
||||
};
|
||||
|
||||
static CURLcode cr_eob_init(struct Curl_easy *data,
|
||||
struct Curl_creader *reader)
|
||||
{
|
||||
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;
|
||||
|
||||
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);
|
||||
CURL_TRC_SMTP(data, "cr_eob_read, next_read(len=%zu) -> %d, %zu eos=%d",
|
||||
blen, result, nread, eos);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
if(buf[i] != SMTP_EOB[ctx->n_eob])
|
||||
ctx->n_eob = 0;
|
||||
|
||||
if(buf[i] == SMTP_EOB[ctx->n_eob]) {
|
||||
/* matching another char of the EOB */
|
||||
++ctx->n_eob;
|
||||
}
|
||||
}
|
||||
|
||||
/* add any remainder to buf */
|
||||
if(start < nread) {
|
||||
result = Curl_bufq_cwrite(&ctx->buf, buf + start, nread - start, &n);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*peos = FALSE;
|
||||
|
||||
if(ctx->read_eos && !ctx->processed_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;
|
||||
CURL_TRC_SMTP(data, "auto-ending mail body with '\\r\\n.\\r\\n'");
|
||||
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 escape the last '.' */
|
||||
eob = "." SMTP_EOB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
result = Curl_bufq_cwrite(&ctx->buf, eob, strlen(eob), &n);
|
||||
if(result)
|
||||
return result;
|
||||
ctx->processed_eos = TRUE;
|
||||
}
|
||||
|
||||
if(!Curl_bufq_is_empty(&ctx->buf)) {
|
||||
result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
|
||||
}
|
||||
else
|
||||
*pnread = 0;
|
||||
|
||||
if(ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
|
||||
/* no more data, read all, done. */
|
||||
CURL_TRC_SMTP(data, "mail body complete, returning EOS");
|
||||
ctx->eos = TRUE;
|
||||
}
|
||||
*peos = ctx->eos;
|
||||
DEBUGF(infof(data, "cr_eob_read(%zu) -> %d, %zd, %d",
|
||||
blen, result, *pnread, *peos));
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_cntrl,
|
||||
Curl_creader_def_is_paused,
|
||||
Curl_creader_def_done,
|
||||
sizeof(struct cr_eob_ctx)
|
||||
#ifdef USE_SSL
|
||||
/*
|
||||
* SMTPS protocol handler.
|
||||
*/
|
||||
const struct Curl_handler Curl_handler_smtps = {
|
||||
"smtps", /* scheme */
|
||||
smtp_setup_connection, /* setup_connection */
|
||||
smtp_do, /* do_it */
|
||||
smtp_done, /* done */
|
||||
ZERO_NULL, /* do_more */
|
||||
smtp_connect, /* connect_it */
|
||||
smtp_multi_statemach, /* connecting */
|
||||
smtp_doing, /* doing */
|
||||
smtp_pollset, /* proto_pollset */
|
||||
smtp_pollset, /* doing_pollset */
|
||||
ZERO_NULL, /* domore_pollset */
|
||||
ZERO_NULL, /* perform_pollset */
|
||||
smtp_disconnect, /* disconnect */
|
||||
ZERO_NULL, /* write_resp */
|
||||
ZERO_NULL, /* write_resp_hd */
|
||||
ZERO_NULL, /* connection_check */
|
||||
ZERO_NULL, /* attach connection */
|
||||
ZERO_NULL, /* follow */
|
||||
PORT_SMTPS, /* defport */
|
||||
CURLPROTO_SMTPS, /* protocol */
|
||||
CURLPROTO_SMTP, /* family */
|
||||
PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
|
||||
PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS | PROTOPT_CONN_REUSE
|
||||
};
|
||||
|
||||
static CURLcode cr_eob_add(struct Curl_easy *data)
|
||||
{
|
||||
struct Curl_creader *reader = NULL;
|
||||
CURLcode result;
|
||||
|
||||
result = Curl_creader_create(&reader, data, &cr_eob, CURL_CR_CONTENT_ENCODE);
|
||||
if(!result)
|
||||
result = Curl_creader_add(data, reader);
|
||||
|
||||
if(result && reader)
|
||||
Curl_creader_free(data, reader);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CURL_DISABLE_SMTP */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user