Annotation of embedaddon/curl/lib/smtp.c, revision 1.1.1.1

1.1       misho       1: /***************************************************************************
                      2:  *                                  _   _ ____  _
                      3:  *  Project                     ___| | | |  _ \| |
                      4:  *                             / __| | | | |_) | |
                      5:  *                            | (__| |_| |  _ <| |___
                      6:  *                             \___|\___/|_| \_\_____|
                      7:  *
                      8:  * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
                      9:  *
                     10:  * This software is licensed as described in the file COPYING, which
                     11:  * you should have received as part of this distribution. The terms
                     12:  * are also available at https://curl.haxx.se/docs/copyright.html.
                     13:  *
                     14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
                     15:  * copies of the Software, and permit persons to whom the Software is
                     16:  * furnished to do so, under the terms of the COPYING file.
                     17:  *
                     18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
                     19:  * KIND, either express or implied.
                     20:  *
                     21:  * RFC1870 SMTP Service Extension for Message Size
                     22:  * RFC2195 CRAM-MD5 authentication
                     23:  * RFC2831 DIGEST-MD5 authentication
                     24:  * RFC3207 SMTP over TLS
                     25:  * RFC4422 Simple Authentication and Security Layer (SASL)
                     26:  * RFC4616 PLAIN authentication
                     27:  * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
                     28:  * RFC4954 SMTP Authentication
                     29:  * RFC5321 SMTP protocol
                     30:  * RFC5890 Internationalized Domain Names for Applications (IDNA)
                     31:  * RFC6531 SMTP Extension for Internationalized Email
                     32:  * RFC6532 Internationalized Email Headers
                     33:  * RFC6749 OAuth 2.0 Authorization Framework
                     34:  * RFC8314 Use of TLS for Email Submission and Access
                     35:  * Draft   SMTP URL Interface   <draft-earhart-url-smtp-00.txt>
                     36:  * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
                     37:  *
                     38:  ***************************************************************************/
                     39: 
                     40: #include "curl_setup.h"
                     41: 
                     42: #ifndef CURL_DISABLE_SMTP
                     43: 
                     44: #ifdef HAVE_NETINET_IN_H
                     45: #include <netinet/in.h>
                     46: #endif
                     47: #ifdef HAVE_ARPA_INET_H
                     48: #include <arpa/inet.h>
                     49: #endif
                     50: #ifdef HAVE_UTSNAME_H
                     51: #include <sys/utsname.h>
                     52: #endif
                     53: #ifdef HAVE_NETDB_H
                     54: #include <netdb.h>
                     55: #endif
                     56: #ifdef __VMS
                     57: #include <in.h>
                     58: #include <inet.h>
                     59: #endif
                     60: 
                     61: #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
                     62: #undef in_addr_t
                     63: #define in_addr_t unsigned long
                     64: #endif
                     65: 
                     66: #include <curl/curl.h>
                     67: #include "urldata.h"
                     68: #include "sendf.h"
                     69: #include "hostip.h"
                     70: #include "progress.h"
                     71: #include "transfer.h"
                     72: #include "escape.h"
                     73: #include "http.h" /* for HTTP proxy tunnel stuff */
                     74: #include "mime.h"
                     75: #include "socks.h"
                     76: #include "smtp.h"
                     77: #include "strtoofft.h"
                     78: #include "strcase.h"
                     79: #include "vtls/vtls.h"
                     80: #include "connect.h"
                     81: #include "strerror.h"
                     82: #include "select.h"
                     83: #include "multiif.h"
                     84: #include "url.h"
                     85: #include "curl_gethostname.h"
                     86: #include "curl_sasl.h"
                     87: #include "warnless.h"
                     88: /* The last 3 #include files should be in this order */
                     89: #include "curl_printf.h"
                     90: #include "curl_memory.h"
                     91: #include "memdebug.h"
                     92: 
                     93: /* Local API functions */
                     94: static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
                     95: static CURLcode smtp_do(struct connectdata *conn, bool *done);
                     96: static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
                     97:                           bool premature);
                     98: static CURLcode smtp_connect(struct connectdata *conn, bool *done);
                     99: static CURLcode smtp_disconnect(struct connectdata *conn, bool dead);
                    100: static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
                    101: static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks);
                    102: static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
                    103: static CURLcode smtp_setup_connection(struct connectdata *conn);
                    104: static CURLcode smtp_parse_url_options(struct connectdata *conn);
                    105: static CURLcode smtp_parse_url_path(struct connectdata *conn);
                    106: static CURLcode smtp_parse_custom_request(struct connectdata *conn);
                    107: static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
                    108:                                    char **address, struct hostname *host);
                    109: static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech,
                    110:                                   const char *initresp);
                    111: static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp);
                    112: static void smtp_get_message(char *buffer, char **outptr);
                    113: 
                    114: /*
                    115:  * SMTP protocol handler.
                    116:  */
                    117: 
                    118: const struct Curl_handler Curl_handler_smtp = {
                    119:   "SMTP",                           /* scheme */
                    120:   smtp_setup_connection,            /* setup_connection */
                    121:   smtp_do,                          /* do_it */
                    122:   smtp_done,                        /* done */
                    123:   ZERO_NULL,                        /* do_more */
                    124:   smtp_connect,                     /* connect_it */
                    125:   smtp_multi_statemach,             /* connecting */
                    126:   smtp_doing,                       /* doing */
                    127:   smtp_getsock,                     /* proto_getsock */
                    128:   smtp_getsock,                     /* doing_getsock */
                    129:   ZERO_NULL,                        /* domore_getsock */
                    130:   ZERO_NULL,                        /* perform_getsock */
                    131:   smtp_disconnect,                  /* disconnect */
                    132:   ZERO_NULL,                        /* readwrite */
                    133:   ZERO_NULL,                        /* connection_check */
                    134:   PORT_SMTP,                        /* defport */
                    135:   CURLPROTO_SMTP,                   /* protocol */
                    136:   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
                    137:   PROTOPT_URLOPTIONS
                    138: };
                    139: 
                    140: #ifdef USE_SSL
                    141: /*
                    142:  * SMTPS protocol handler.
                    143:  */
                    144: 
                    145: const struct Curl_handler Curl_handler_smtps = {
                    146:   "SMTPS",                          /* scheme */
                    147:   smtp_setup_connection,            /* setup_connection */
                    148:   smtp_do,                          /* do_it */
                    149:   smtp_done,                        /* done */
                    150:   ZERO_NULL,                        /* do_more */
                    151:   smtp_connect,                     /* connect_it */
                    152:   smtp_multi_statemach,             /* connecting */
                    153:   smtp_doing,                       /* doing */
                    154:   smtp_getsock,                     /* proto_getsock */
                    155:   smtp_getsock,                     /* doing_getsock */
                    156:   ZERO_NULL,                        /* domore_getsock */
                    157:   ZERO_NULL,                        /* perform_getsock */
                    158:   smtp_disconnect,                  /* disconnect */
                    159:   ZERO_NULL,                        /* readwrite */
                    160:   ZERO_NULL,                        /* connection_check */
                    161:   PORT_SMTPS,                       /* defport */
                    162:   CURLPROTO_SMTPS,                  /* protocol */
                    163:   PROTOPT_CLOSEACTION | PROTOPT_SSL
                    164:   | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
                    165: };
                    166: #endif
                    167: 
                    168: /* SASL parameters for the smtp protocol */
                    169: static const struct SASLproto saslsmtp = {
                    170:   "smtp",                     /* The service name */
                    171:   334,                        /* Code received when continuation is expected */
                    172:   235,                        /* Code to receive upon authentication success */
                    173:   512 - 8,                    /* Maximum initial response length (no max) */
                    174:   smtp_perform_auth,          /* Send authentication command */
                    175:   smtp_continue_auth,         /* Send authentication continuation */
                    176:   smtp_get_message            /* Get SASL response message */
                    177: };
                    178: 
                    179: #ifdef USE_SSL
                    180: static void smtp_to_smtps(struct connectdata *conn)
                    181: {
                    182:   /* Change the connection handler */
                    183:   conn->handler = &Curl_handler_smtps;
                    184: 
                    185:   /* Set the connection's upgraded to TLS flag */
                    186:   conn->tls_upgraded = TRUE;
                    187: }
                    188: #else
                    189: #define smtp_to_smtps(x) Curl_nop_stmt
                    190: #endif
                    191: 
                    192: /***********************************************************************
                    193:  *
                    194:  * smtp_endofresp()
                    195:  *
                    196:  * Checks for an ending SMTP status code at the start of the given string, but
                    197:  * also detects various capabilities from the EHLO response including the
                    198:  * supported authentication mechanisms.
                    199:  */
                    200: static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
                    201:                            int *resp)
                    202: {
                    203:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                    204:   bool result = FALSE;
                    205: 
                    206:   /* Nothing for us */
                    207:   if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
                    208:     return FALSE;
                    209: 
                    210:   /* Do we have a command response? This should be the response code followed
                    211:      by a space and optionally some text as per RFC-5321 and as outlined in
                    212:      Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
                    213:      only send the response code instead as per Section 4.2. */
                    214:   if(line[3] == ' ' || len == 5) {
                    215:     char tmpline[6];
                    216: 
                    217:     result = TRUE;
                    218:     memset(tmpline, '\0', sizeof(tmpline));
                    219:     memcpy(tmpline, line, (len == 5 ? 5 : 3));
                    220:     *resp = curlx_sltosi(strtol(tmpline, NULL, 10));
                    221: 
                    222:     /* Make sure real server never sends internal value */
                    223:     if(*resp == 1)
                    224:       *resp = 0;
                    225:   }
                    226:   /* Do we have a multiline (continuation) response? */
                    227:   else if(line[3] == '-' &&
                    228:           (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) {
                    229:     result = TRUE;
                    230:     *resp = 1;  /* Internal response code */
                    231:   }
                    232: 
                    233:   return result;
                    234: }
                    235: 
                    236: /***********************************************************************
                    237:  *
                    238:  * smtp_get_message()
                    239:  *
                    240:  * Gets the authentication message from the response buffer.
                    241:  */
                    242: static void smtp_get_message(char *buffer, char **outptr)
                    243: {
                    244:   size_t len = strlen(buffer);
                    245:   char *message = NULL;
                    246: 
                    247:   if(len > 4) {
                    248:     /* Find the start of the message */
                    249:     len -= 4;
                    250:     for(message = buffer + 4; *message == ' ' || *message == '\t';
                    251:         message++, len--)
                    252:       ;
                    253: 
                    254:     /* Find the end of the message */
                    255:     for(; len--;)
                    256:       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
                    257:          message[len] != '\t')
                    258:         break;
                    259: 
                    260:     /* Terminate the message */
                    261:     if(++len) {
                    262:       message[len] = '\0';
                    263:     }
                    264:   }
                    265:   else
                    266:     /* junk input => zero length output */
                    267:     message = &buffer[len];
                    268: 
                    269:   *outptr = message;
                    270: }
                    271: 
                    272: /***********************************************************************
                    273:  *
                    274:  * state()
                    275:  *
                    276:  * This is the ONLY way to change SMTP state!
                    277:  */
                    278: static void state(struct connectdata *conn, smtpstate newstate)
                    279: {
                    280:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                    281: #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
                    282:   /* for debug purposes */
                    283:   static const char * const names[] = {
                    284:     "STOP",
                    285:     "SERVERGREET",
                    286:     "EHLO",
                    287:     "HELO",
                    288:     "STARTTLS",
                    289:     "UPGRADETLS",
                    290:     "AUTH",
                    291:     "COMMAND",
                    292:     "MAIL",
                    293:     "RCPT",
                    294:     "DATA",
                    295:     "POSTDATA",
                    296:     "QUIT",
                    297:     /* LAST */
                    298:   };
                    299: 
                    300:   if(smtpc->state != newstate)
                    301:     infof(conn->data, "SMTP %p state change from %s to %s\n",
                    302:           (void *)smtpc, names[smtpc->state], names[newstate]);
                    303: #endif
                    304: 
                    305:   smtpc->state = newstate;
                    306: }
                    307: 
                    308: /***********************************************************************
                    309:  *
                    310:  * smtp_perform_ehlo()
                    311:  *
                    312:  * Sends the EHLO command to not only initialise communication with the ESMTP
                    313:  * server but to also obtain a list of server side supported capabilities.
                    314:  */
                    315: static CURLcode smtp_perform_ehlo(struct connectdata *conn)
                    316: {
                    317:   CURLcode result = CURLE_OK;
                    318:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                    319: 
                    320:   smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */
                    321:   smtpc->sasl.authused = SASL_AUTH_NONE;  /* Clear the authentication mechanism
                    322:                                              used for esmtp connections */
                    323:   smtpc->tls_supported = FALSE;           /* Clear the TLS capability */
                    324:   smtpc->auth_supported = FALSE;          /* Clear the AUTH capability */
                    325: 
                    326:   /* Send the EHLO command */
                    327:   result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
                    328: 
                    329:   if(!result)
                    330:     state(conn, SMTP_EHLO);
                    331: 
                    332:   return result;
                    333: }
                    334: 
                    335: /***********************************************************************
                    336:  *
                    337:  * smtp_perform_helo()
                    338:  *
                    339:  * Sends the HELO command to initialise communication with the SMTP server.
                    340:  */
                    341: static CURLcode smtp_perform_helo(struct connectdata *conn)
                    342: {
                    343:   CURLcode result = CURLE_OK;
                    344:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                    345: 
                    346:   smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used
                    347:                                             in smtp connections */
                    348: 
                    349:   /* Send the HELO command */
                    350:   result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
                    351: 
                    352:   if(!result)
                    353:     state(conn, SMTP_HELO);
                    354: 
                    355:   return result;
                    356: }
                    357: 
                    358: /***********************************************************************
                    359:  *
                    360:  * smtp_perform_starttls()
                    361:  *
                    362:  * Sends the STLS command to start the upgrade to TLS.
                    363:  */
                    364: static CURLcode smtp_perform_starttls(struct connectdata *conn)
                    365: {
                    366:   /* Send the STARTTLS command */
                    367:   CURLcode result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS");
                    368: 
                    369:   if(!result)
                    370:     state(conn, SMTP_STARTTLS);
                    371: 
                    372:   return result;
                    373: }
                    374: 
                    375: /***********************************************************************
                    376:  *
                    377:  * smtp_perform_upgrade_tls()
                    378:  *
                    379:  * Performs the upgrade to TLS.
                    380:  */
                    381: static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
                    382: {
                    383:   /* Start the SSL connection */
                    384:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                    385:   CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
                    386:                                                  &smtpc->ssldone);
                    387: 
                    388:   if(!result) {
                    389:     if(smtpc->state != SMTP_UPGRADETLS)
                    390:       state(conn, SMTP_UPGRADETLS);
                    391: 
                    392:     if(smtpc->ssldone) {
                    393:       smtp_to_smtps(conn);
                    394:       result = smtp_perform_ehlo(conn);
                    395:     }
                    396:   }
                    397: 
                    398:   return result;
                    399: }
                    400: 
                    401: /***********************************************************************
                    402:  *
                    403:  * smtp_perform_auth()
                    404:  *
                    405:  * Sends an AUTH command allowing the client to login with the given SASL
                    406:  * authentication mechanism.
                    407:  */
                    408: static CURLcode smtp_perform_auth(struct connectdata *conn,
                    409:                                   const char *mech,
                    410:                                   const char *initresp)
                    411: {
                    412:   CURLcode result = CURLE_OK;
                    413:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                    414: 
                    415:   if(initresp) {                                  /* AUTH <mech> ...<crlf> */
                    416:     /* Send the AUTH command with the initial response */
                    417:     result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
                    418:   }
                    419:   else {
                    420:     /* Send the AUTH command */
                    421:     result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
                    422:   }
                    423: 
                    424:   return result;
                    425: }
                    426: 
                    427: /***********************************************************************
                    428:  *
                    429:  * smtp_continue_auth()
                    430:  *
                    431:  * Sends SASL continuation data or cancellation.
                    432:  */
                    433: static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp)
                    434: {
                    435:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                    436: 
                    437:   return Curl_pp_sendf(&smtpc->pp, "%s", resp);
                    438: }
                    439: 
                    440: /***********************************************************************
                    441:  *
                    442:  * smtp_perform_authentication()
                    443:  *
                    444:  * Initiates the authentication sequence, with the appropriate SASL
                    445:  * authentication mechanism.
                    446:  */
                    447: static CURLcode smtp_perform_authentication(struct connectdata *conn)
                    448: {
                    449:   CURLcode result = CURLE_OK;
                    450:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                    451:   saslprogress progress;
                    452: 
                    453:   /* Check we have enough data to authenticate with, and the
                    454:      server supports authentiation, and end the connect phase if not */
                    455:   if(!smtpc->auth_supported ||
                    456:      !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
                    457:     state(conn, SMTP_STOP);
                    458:     return result;
                    459:   }
                    460: 
                    461:   /* Calculate the SASL login details */
                    462:   result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress);
                    463: 
                    464:   if(!result) {
                    465:     if(progress == SASL_INPROGRESS)
                    466:       state(conn, SMTP_AUTH);
                    467:     else {
                    468:       /* Other mechanisms not supported */
                    469:       infof(conn->data, "No known authentication mechanisms supported!\n");
                    470:       result = CURLE_LOGIN_DENIED;
                    471:     }
                    472:   }
                    473: 
                    474:   return result;
                    475: }
                    476: 
                    477: /***********************************************************************
                    478:  *
                    479:  * smtp_perform_command()
                    480:  *
                    481:  * Sends a SMTP based command.
                    482:  */
                    483: static CURLcode smtp_perform_command(struct connectdata *conn)
                    484: {
                    485:   CURLcode result = CURLE_OK;
                    486:   struct Curl_easy *data = conn->data;
                    487:   struct SMTP *smtp = data->req.protop;
                    488: 
                    489:   if(smtp->rcpt) {
                    490:     /* We notify the server we are sending UTF-8 data if a) it supports the
                    491:        SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in
                    492:        either the local address or host name parts. This is regardless of
                    493:        whether the host name is encoded using IDN ACE */
                    494:     bool utf8 = FALSE;
                    495: 
                    496:     if((!smtp->custom) || (!smtp->custom[0])) {
                    497:       char *address = NULL;
                    498:       struct hostname host = { NULL, NULL, NULL, NULL };
                    499: 
                    500:       /* Parse the mailbox to verify into the local address and host name
                    501:          parts, converting the host name to an IDN A-label if necessary */
                    502:       result = smtp_parse_address(conn, smtp->rcpt->data,
                    503:                                   &address, &host);
                    504:       if(result)
                    505:         return result;
                    506: 
                    507:       /* Establish whether we should report SMTPUTF8 to the server for this
                    508:          mailbox as per RFC-6531 sect. 3.1 point 6 */
                    509:       utf8 = (conn->proto.smtpc.utf8_supported) &&
                    510:              ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
                    511:               (!Curl_is_ASCII_name(host.name)));
                    512: 
                    513:       /* Send the VRFY command (Note: The host name part may be absent when the
                    514:          host is a local system) */
                    515:       result = Curl_pp_sendf(&conn->proto.smtpc.pp, "VRFY %s%s%s%s",
                    516:                              address,
                    517:                              host.name ? "@" : "",
                    518:                              host.name ? host.name : "",
                    519:                              utf8 ? " SMTPUTF8" : "");
                    520: 
                    521:       Curl_free_idnconverted_hostname(&host);
                    522:       free(address);
                    523:     }
                    524:     else {
                    525:       /* Establish whether we should report that we support SMTPUTF8 for EXPN
                    526:          commands to the server as per RFC-6531 sect. 3.1 point 6 */
                    527:       utf8 = (conn->proto.smtpc.utf8_supported) &&
                    528:              (!strcmp(smtp->custom, "EXPN"));
                    529: 
                    530:       /* Send the custom recipient based command such as the EXPN command */
                    531:       result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s%s", smtp->custom,
                    532:                              smtp->rcpt->data,
                    533:                              utf8 ? " SMTPUTF8" : "");
                    534:     }
                    535:   }
                    536:   else
                    537:     /* Send the non-recipient based command such as HELP */
                    538:     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
                    539:                            smtp->custom && smtp->custom[0] != '\0' ?
                    540:                            smtp->custom : "HELP");
                    541: 
                    542:   if(!result)
                    543:     state(conn, SMTP_COMMAND);
                    544: 
                    545:   return result;
                    546: }
                    547: 
                    548: /***********************************************************************
                    549:  *
                    550:  * smtp_perform_mail()
                    551:  *
                    552:  * Sends an MAIL command to initiate the upload of a message.
                    553:  */
                    554: static CURLcode smtp_perform_mail(struct connectdata *conn)
                    555: {
                    556:   char *from = NULL;
                    557:   char *auth = NULL;
                    558:   char *size = NULL;
                    559:   CURLcode result = CURLE_OK;
                    560:   struct Curl_easy *data = conn->data;
                    561: 
                    562:   /* We notify the server we are sending UTF-8 data if a) it supports the
                    563:      SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in
                    564:      either the local address or host name parts. This is regardless of
                    565:      whether the host name is encoded using IDN ACE */
                    566:   bool utf8 = FALSE;
                    567: 
                    568:   /* Calculate the FROM parameter */
                    569:   if(data->set.str[STRING_MAIL_FROM]) {
                    570:     char *address = NULL;
                    571:     struct hostname host = { NULL, NULL, NULL, NULL };
                    572: 
                    573:     /* Parse the FROM mailbox into the local address and host name parts,
                    574:        converting the host name to an IDN A-label if necessary */
                    575:     result = smtp_parse_address(conn, data->set.str[STRING_MAIL_FROM],
                    576:                                 &address, &host);
                    577:     if(result)
                    578:       return result;
                    579: 
                    580:     /* Establish whether we should report SMTPUTF8 to the server for this
                    581:        mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
                    582:     utf8 = (conn->proto.smtpc.utf8_supported) &&
                    583:            ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
                    584:             (!Curl_is_ASCII_name(host.name)));
                    585: 
                    586:     if(host.name) {
                    587:       from = aprintf("<%s@%s>", address, host.name);
                    588: 
                    589:       Curl_free_idnconverted_hostname(&host);
                    590:     }
                    591:     else
                    592:       /* An invalid mailbox was provided but we'll simply let the server worry
                    593:          about that and reply with a 501 error */
                    594:       from = aprintf("<%s>", address);
                    595: 
                    596:     free(address);
                    597:   }
                    598:   else
                    599:     /* Null reverse-path, RFC-5321, sect. 3.6.3 */
                    600:     from = strdup("<>");
                    601: 
                    602:   if(!from)
                    603:     return CURLE_OUT_OF_MEMORY;
                    604: 
                    605:   /* Calculate the optional AUTH parameter */
                    606:   if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
                    607:     if(data->set.str[STRING_MAIL_AUTH][0] != '\0') {
                    608:       char *address = NULL;
                    609:       struct hostname host = { NULL, NULL, NULL, NULL };
                    610: 
                    611:       /* Parse the AUTH mailbox into the local address and host name parts,
                    612:          converting the host name to an IDN A-label if necessary */
                    613:       result = smtp_parse_address(conn, data->set.str[STRING_MAIL_AUTH],
                    614:                                   &address, &host);
                    615:       if(result) {
                    616:         free(from);
                    617:         return result;
                    618:       }
                    619: 
                    620:       /* Establish whether we should report SMTPUTF8 to the server for this
                    621:          mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
                    622:       if((!utf8) && (conn->proto.smtpc.utf8_supported) &&
                    623:          ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
                    624:           (!Curl_is_ASCII_name(host.name))))
                    625:         utf8 = TRUE;
                    626: 
                    627:       if(host.name) {
                    628:         auth = aprintf("<%s@%s>", address, host.name);
                    629: 
                    630:         Curl_free_idnconverted_hostname(&host);
                    631:       }
                    632:       else
                    633:         /* An invalid mailbox was provided but we'll simply let the server
                    634:            worry about it */
                    635:         auth = aprintf("<%s>", address);
                    636: 
                    637:       free(address);
                    638:     }
                    639:     else
                    640:       /* Empty AUTH, RFC-2554, sect. 5 */
                    641:       auth = strdup("<>");
                    642: 
                    643:     if(!auth) {
                    644:       free(from);
                    645: 
                    646:       return CURLE_OUT_OF_MEMORY;
                    647:     }
                    648:   }
                    649: 
                    650:   /* Prepare the mime data if some. */
                    651:   if(data->set.mimepost.kind != MIMEKIND_NONE) {
                    652:     /* Use the whole structure as data. */
                    653:     data->set.mimepost.flags &= ~MIME_BODY_ONLY;
                    654: 
                    655:     /* Add external headers and mime version. */
                    656:     curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
                    657:     result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
                    658:                                        NULL, MIMESTRATEGY_MAIL);
                    659: 
                    660:     if(!result)
                    661:       if(!Curl_checkheaders(conn, "Mime-Version"))
                    662:         result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
                    663:                                       "Mime-Version: 1.0");
                    664: 
                    665:     /* Make sure we will read the entire mime structure. */
                    666:     if(!result)
                    667:       result = Curl_mime_rewind(&data->set.mimepost);
                    668: 
                    669:     if(result) {
                    670:       free(from);
                    671:       free(auth);
                    672: 
                    673:       return result;
                    674:     }
                    675: 
                    676:     data->state.infilesize = Curl_mime_size(&data->set.mimepost);
                    677: 
                    678:     /* Read from mime structure. */
                    679:     data->state.fread_func = (curl_read_callback) Curl_mime_read;
                    680:     data->state.in = (void *) &data->set.mimepost;
                    681:   }
                    682: 
                    683:   /* Calculate the optional SIZE parameter */
                    684:   if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
                    685:     size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
                    686: 
                    687:     if(!size) {
                    688:       free(from);
                    689:       free(auth);
                    690: 
                    691:       return CURLE_OUT_OF_MEMORY;
                    692:     }
                    693:   }
                    694: 
                    695:   /* If the mailboxes in the FROM and AUTH parameters don't include a UTF-8
                    696:      based address then quickly scan through the recipient list and check if
                    697:      any there do, as we need to correctly identify our support for SMTPUTF8
                    698:      in the envelope, as per RFC-6531 sect. 3.4 */
                    699:   if(conn->proto.smtpc.utf8_supported && !utf8) {
                    700:     struct SMTP *smtp = data->req.protop;
                    701:     struct curl_slist *rcpt = smtp->rcpt;
                    702: 
                    703:     while(rcpt && !utf8) {
                    704:       /* Does the host name contain non-ASCII characters? */
                    705:       if(!Curl_is_ASCII_name(rcpt->data))
                    706:         utf8 = TRUE;
                    707: 
                    708:       rcpt = rcpt->next;
                    709:     }
                    710:   }
                    711: 
                    712:   /* Send the MAIL command */
                    713:   result = Curl_pp_sendf(&conn->proto.smtpc.pp,
                    714:                          "MAIL FROM:%s%s%s%s%s%s",
                    715:                          from,                 /* Mandatory                 */
                    716:                          auth ? " AUTH=" : "", /* Optional on AUTH support  */
                    717:                          auth ? auth : "",     /*                           */
                    718:                          size ? " SIZE=" : "", /* Optional on SIZE support  */
                    719:                          size ? size : "",     /*                           */
                    720:                          utf8 ? " SMTPUTF8"    /* Internationalised mailbox */
                    721:                                : "");          /* included in our envelope  */
                    722: 
                    723:   free(from);
                    724:   free(auth);
                    725:   free(size);
                    726: 
                    727:   if(!result)
                    728:     state(conn, SMTP_MAIL);
                    729: 
                    730:   return result;
                    731: }
                    732: 
                    733: /***********************************************************************
                    734:  *
                    735:  * smtp_perform_rcpt_to()
                    736:  *
                    737:  * Sends a RCPT TO command for a given recipient as part of the message upload
                    738:  * process.
                    739:  */
                    740: static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
                    741: {
                    742:   CURLcode result = CURLE_OK;
                    743:   struct Curl_easy *data = conn->data;
                    744:   struct SMTP *smtp = data->req.protop;
                    745:   char *address = NULL;
                    746:   struct hostname host = { NULL, NULL, NULL, NULL };
                    747: 
                    748:   /* Parse the recipient mailbox into the local address and host name parts,
                    749:      converting the host name to an IDN A-label if necessary */
                    750:   result = smtp_parse_address(conn, smtp->rcpt->data,
                    751:                               &address, &host);
                    752:   if(result)
                    753:     return result;
                    754: 
                    755:   /* Send the RCPT TO command */
                    756:   if(host.name)
                    757:     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s@%s>", address,
                    758:                            host.name);
                    759:   else
                    760:     /* An invalid mailbox was provided but we'll simply let the server worry
                    761:        about that and reply with a 501 error */
                    762:     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>", address);
                    763: 
                    764:   Curl_free_idnconverted_hostname(&host);
                    765:   free(address);
                    766: 
                    767:   if(!result)
                    768:     state(conn, SMTP_RCPT);
                    769: 
                    770:   return result;
                    771: }
                    772: 
                    773: /***********************************************************************
                    774:  *
                    775:  * smtp_perform_quit()
                    776:  *
                    777:  * Performs the quit action prior to sclose() being called.
                    778:  */
                    779: static CURLcode smtp_perform_quit(struct connectdata *conn)
                    780: {
                    781:   /* Send the QUIT command */
                    782:   CURLcode result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT");
                    783: 
                    784:   if(!result)
                    785:     state(conn, SMTP_QUIT);
                    786: 
                    787:   return result;
                    788: }
                    789: 
                    790: /* For the initial server greeting */
                    791: static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
                    792:                                             int smtpcode,
                    793:                                             smtpstate instate)
                    794: {
                    795:   CURLcode result = CURLE_OK;
                    796:   struct Curl_easy *data = conn->data;
                    797: 
                    798:   (void)instate; /* no use for this yet */
                    799: 
                    800:   if(smtpcode/100 != 2) {
                    801:     failf(data, "Got unexpected smtp-server response: %d", smtpcode);
                    802:     result = CURLE_WEIRD_SERVER_REPLY;
                    803:   }
                    804:   else
                    805:     result = smtp_perform_ehlo(conn);
                    806: 
                    807:   return result;
                    808: }
                    809: 
                    810: /* For STARTTLS responses */
                    811: static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
                    812:                                          int smtpcode,
                    813:                                          smtpstate instate)
                    814: {
                    815:   CURLcode result = CURLE_OK;
                    816:   struct Curl_easy *data = conn->data;
                    817: 
                    818:   (void)instate; /* no use for this yet */
                    819: 
                    820:   if(smtpcode != 220) {
                    821:     if(data->set.use_ssl != CURLUSESSL_TRY) {
                    822:       failf(data, "STARTTLS denied, code %d", smtpcode);
                    823:       result = CURLE_USE_SSL_FAILED;
                    824:     }
                    825:     else
                    826:       result = smtp_perform_authentication(conn);
                    827:   }
                    828:   else
                    829:     result = smtp_perform_upgrade_tls(conn);
                    830: 
                    831:   return result;
                    832: }
                    833: 
                    834: /* For EHLO responses */
                    835: static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
                    836:                                      smtpstate instate)
                    837: {
                    838:   CURLcode result = CURLE_OK;
                    839:   struct Curl_easy *data = conn->data;
                    840:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                    841:   const char *line = data->state.buffer;
                    842:   size_t len = strlen(line);
                    843: 
                    844:   (void)instate; /* no use for this yet */
                    845: 
                    846:   if(smtpcode/100 != 2 && smtpcode != 1) {
                    847:     if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use)
                    848:       result = smtp_perform_helo(conn);
                    849:     else {
                    850:       failf(data, "Remote access denied: %d", smtpcode);
                    851:       result = CURLE_REMOTE_ACCESS_DENIED;
                    852:     }
                    853:   }
                    854:   else if(len >= 4) {
                    855:     line += 4;
                    856:     len -= 4;
                    857: 
                    858:     /* Does the server support the STARTTLS capability? */
                    859:     if(len >= 8 && !memcmp(line, "STARTTLS", 8))
                    860:       smtpc->tls_supported = TRUE;
                    861: 
                    862:     /* Does the server support the SIZE capability? */
                    863:     else if(len >= 4 && !memcmp(line, "SIZE", 4))
                    864:       smtpc->size_supported = TRUE;
                    865: 
                    866:     /* Does the server support the UTF-8 capability? */
                    867:     else if(len >= 8 && !memcmp(line, "SMTPUTF8", 8))
                    868:       smtpc->utf8_supported = TRUE;
                    869: 
                    870:     /* Does the server support authentication? */
                    871:     else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
                    872:       smtpc->auth_supported = TRUE;
                    873: 
                    874:       /* Advance past the AUTH keyword */
                    875:       line += 5;
                    876:       len -= 5;
                    877: 
                    878:       /* Loop through the data line */
                    879:       for(;;) {
                    880:         size_t llen;
                    881:         size_t wordlen;
                    882:         unsigned int mechbit;
                    883: 
                    884:         while(len &&
                    885:               (*line == ' ' || *line == '\t' ||
                    886:                *line == '\r' || *line == '\n')) {
                    887: 
                    888:           line++;
                    889:           len--;
                    890:         }
                    891: 
                    892:         if(!len)
                    893:           break;
                    894: 
                    895:         /* Extract the word */
                    896:         for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
                    897:               line[wordlen] != '\t' && line[wordlen] != '\r' &&
                    898:               line[wordlen] != '\n';)
                    899:           wordlen++;
                    900: 
                    901:         /* Test the word for a matching authentication mechanism */
                    902:         mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
                    903:         if(mechbit && llen == wordlen)
                    904:           smtpc->sasl.authmechs |= mechbit;
                    905: 
                    906:         line += wordlen;
                    907:         len -= wordlen;
                    908:       }
                    909:     }
                    910: 
                    911:     if(smtpcode != 1) {
                    912:       if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
                    913:         /* We don't have a SSL/TLS connection yet, but SSL is requested */
                    914:         if(smtpc->tls_supported)
                    915:           /* Switch to TLS connection now */
                    916:           result = smtp_perform_starttls(conn);
                    917:         else if(data->set.use_ssl == CURLUSESSL_TRY)
                    918:           /* Fallback and carry on with authentication */
                    919:           result = smtp_perform_authentication(conn);
                    920:         else {
                    921:           failf(data, "STARTTLS not supported.");
                    922:           result = CURLE_USE_SSL_FAILED;
                    923:         }
                    924:       }
                    925:       else
                    926:         result = smtp_perform_authentication(conn);
                    927:     }
                    928:   }
                    929:   else {
                    930:     failf(data, "Unexpectedly short EHLO response");
                    931:     result = CURLE_WEIRD_SERVER_REPLY;
                    932:   }
                    933: 
                    934:   return result;
                    935: }
                    936: 
                    937: /* For HELO responses */
                    938: static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
                    939:                                      smtpstate instate)
                    940: {
                    941:   CURLcode result = CURLE_OK;
                    942:   struct Curl_easy *data = conn->data;
                    943: 
                    944:   (void)instate; /* no use for this yet */
                    945: 
                    946:   if(smtpcode/100 != 2) {
                    947:     failf(data, "Remote access denied: %d", smtpcode);
                    948:     result = CURLE_REMOTE_ACCESS_DENIED;
                    949:   }
                    950:   else
                    951:     /* End of connect phase */
                    952:     state(conn, SMTP_STOP);
                    953: 
                    954:   return result;
                    955: }
                    956: 
                    957: /* For SASL authentication responses */
                    958: static CURLcode smtp_state_auth_resp(struct connectdata *conn,
                    959:                                      int smtpcode,
                    960:                                      smtpstate instate)
                    961: {
                    962:   CURLcode result = CURLE_OK;
                    963:   struct Curl_easy *data = conn->data;
                    964:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                    965:   saslprogress progress;
                    966: 
                    967:   (void)instate; /* no use for this yet */
                    968: 
                    969:   result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress);
                    970:   if(!result)
                    971:     switch(progress) {
                    972:     case SASL_DONE:
                    973:       state(conn, SMTP_STOP);  /* Authenticated */
                    974:       break;
                    975:     case SASL_IDLE:            /* No mechanism left after cancellation */
                    976:       failf(data, "Authentication cancelled");
                    977:       result = CURLE_LOGIN_DENIED;
                    978:       break;
                    979:     default:
                    980:       break;
                    981:     }
                    982: 
                    983:   return result;
                    984: }
                    985: 
                    986: /* For command responses */
                    987: static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
                    988:                                         smtpstate instate)
                    989: {
                    990:   CURLcode result = CURLE_OK;
                    991:   struct Curl_easy *data = conn->data;
                    992:   struct SMTP *smtp = data->req.protop;
                    993:   char *line = data->state.buffer;
                    994:   size_t len = strlen(line);
                    995: 
                    996:   (void)instate; /* no use for this yet */
                    997: 
                    998:   if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) ||
                    999:      (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) {
                   1000:     failf(data, "Command failed: %d", smtpcode);
                   1001:     result = CURLE_RECV_ERROR;
                   1002:   }
                   1003:   else {
                   1004:     /* Temporarily add the LF character back and send as body to the client */
                   1005:     if(!data->set.opt_no_body) {
                   1006:       line[len] = '\n';
                   1007:       result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
                   1008:       line[len] = '\0';
                   1009:     }
                   1010: 
                   1011:     if(smtpcode != 1) {
                   1012:       if(smtp->rcpt) {
                   1013:         smtp->rcpt = smtp->rcpt->next;
                   1014: 
                   1015:         if(smtp->rcpt) {
                   1016:           /* Send the next command */
                   1017:           result = smtp_perform_command(conn);
                   1018:         }
                   1019:         else
                   1020:           /* End of DO phase */
                   1021:           state(conn, SMTP_STOP);
                   1022:       }
                   1023:       else
                   1024:         /* End of DO phase */
                   1025:         state(conn, SMTP_STOP);
                   1026:     }
                   1027:   }
                   1028: 
                   1029:   return result;
                   1030: }
                   1031: 
                   1032: /* For MAIL responses */
                   1033: static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
                   1034:                                      smtpstate instate)
                   1035: {
                   1036:   CURLcode result = CURLE_OK;
                   1037:   struct Curl_easy *data = conn->data;
                   1038: 
                   1039:   (void)instate; /* no use for this yet */
                   1040: 
                   1041:   if(smtpcode/100 != 2) {
                   1042:     failf(data, "MAIL failed: %d", smtpcode);
                   1043:     result = CURLE_SEND_ERROR;
                   1044:   }
                   1045:   else
                   1046:     /* Start the RCPT TO command */
                   1047:     result = smtp_perform_rcpt_to(conn);
                   1048: 
                   1049:   return result;
                   1050: }
                   1051: 
                   1052: /* For RCPT responses */
                   1053: static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
                   1054:                                      smtpstate instate)
                   1055: {
                   1056:   CURLcode result = CURLE_OK;
                   1057:   struct Curl_easy *data = conn->data;
                   1058:   struct SMTP *smtp = data->req.protop;
                   1059:   bool is_smtp_err = FALSE;
                   1060:   bool is_smtp_blocking_err = FALSE;
                   1061: 
                   1062:   (void)instate; /* no use for this yet */
                   1063: 
                   1064:   is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE;
                   1065: 
                   1066:   /* If there's multiple RCPT TO to be issued, it's possible to ignore errors
                   1067:      and proceed with only the valid addresses. */
                   1068:   is_smtp_blocking_err =
                   1069:     (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE;
                   1070: 
                   1071:   if(is_smtp_err) {
                   1072:     /* Remembering the last failure which we can report if all "RCPT TO" have
                   1073:        failed and we cannot proceed. */
                   1074:     smtp->rcpt_last_error = smtpcode;
                   1075: 
                   1076:     if(is_smtp_blocking_err) {
                   1077:       failf(data, "RCPT failed: %d", smtpcode);
                   1078:       result = CURLE_SEND_ERROR;
                   1079:     }
                   1080:   }
                   1081:   else {
                   1082:     /* Some RCPT TO commands have succeeded. */
                   1083:     smtp->rcpt_had_ok = TRUE;
                   1084:   }
                   1085: 
                   1086:   if(!is_smtp_blocking_err) {
                   1087:     smtp->rcpt = smtp->rcpt->next;
                   1088: 
                   1089:     if(smtp->rcpt)
                   1090:       /* Send the next RCPT TO command */
                   1091:       result = smtp_perform_rcpt_to(conn);
                   1092:     else {
                   1093:       /* We weren't able to issue a successful RCPT TO command while going
                   1094:          over recipients (potentially multiple). Sending back last error. */
                   1095:       if(!smtp->rcpt_had_ok) {
                   1096:         failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error);
                   1097:         result = CURLE_SEND_ERROR;
                   1098:       }
                   1099:       else {
                   1100:         /* Send the DATA command */
                   1101:         result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
                   1102: 
                   1103:         if(!result)
                   1104:           state(conn, SMTP_DATA);
                   1105:       }
                   1106:     }
                   1107:   }
                   1108: 
                   1109:   return result;
                   1110: }
                   1111: 
                   1112: /* For DATA response */
                   1113: static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
                   1114:                                      smtpstate instate)
                   1115: {
                   1116:   CURLcode result = CURLE_OK;
                   1117:   struct Curl_easy *data = conn->data;
                   1118: 
                   1119:   (void)instate; /* no use for this yet */
                   1120: 
                   1121:   if(smtpcode != 354) {
                   1122:     failf(data, "DATA failed: %d", smtpcode);
                   1123:     result = CURLE_SEND_ERROR;
                   1124:   }
                   1125:   else {
                   1126:     /* Set the progress upload size */
                   1127:     Curl_pgrsSetUploadSize(data, data->state.infilesize);
                   1128: 
                   1129:     /* SMTP upload */
                   1130:     Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
                   1131: 
                   1132:     /* End of DO phase */
                   1133:     state(conn, SMTP_STOP);
                   1134:   }
                   1135: 
                   1136:   return result;
                   1137: }
                   1138: 
                   1139: /* For POSTDATA responses, which are received after the entire DATA
                   1140:    part has been sent to the server */
                   1141: static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
                   1142:                                          int smtpcode,
                   1143:                                          smtpstate instate)
                   1144: {
                   1145:   CURLcode result = CURLE_OK;
                   1146: 
                   1147:   (void)instate; /* no use for this yet */
                   1148: 
                   1149:   if(smtpcode != 250)
                   1150:     result = CURLE_RECV_ERROR;
                   1151: 
                   1152:   /* End of DONE phase */
                   1153:   state(conn, SMTP_STOP);
                   1154: 
                   1155:   return result;
                   1156: }
                   1157: 
                   1158: static CURLcode smtp_statemach_act(struct connectdata *conn)
                   1159: {
                   1160:   CURLcode result = CURLE_OK;
                   1161:   curl_socket_t sock = conn->sock[FIRSTSOCKET];
                   1162:   struct Curl_easy *data = conn->data;
                   1163:   int smtpcode;
                   1164:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                   1165:   struct pingpong *pp = &smtpc->pp;
                   1166:   size_t nread = 0;
                   1167: 
                   1168:   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
                   1169:   if(smtpc->state == SMTP_UPGRADETLS)
                   1170:     return smtp_perform_upgrade_tls(conn);
                   1171: 
                   1172:   /* Flush any data that needs to be sent */
                   1173:   if(pp->sendleft)
                   1174:     return Curl_pp_flushsend(pp);
                   1175: 
                   1176:   do {
                   1177:     /* Read the response from the server */
                   1178:     result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
                   1179:     if(result)
                   1180:       return result;
                   1181: 
                   1182:     /* Store the latest response for later retrieval if necessary */
                   1183:     if(smtpc->state != SMTP_QUIT && smtpcode != 1)
                   1184:       data->info.httpcode = smtpcode;
                   1185: 
                   1186:     if(!smtpcode)
                   1187:       break;
                   1188: 
                   1189:     /* We have now received a full SMTP server response */
                   1190:     switch(smtpc->state) {
                   1191:     case SMTP_SERVERGREET:
                   1192:       result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
                   1193:       break;
                   1194: 
                   1195:     case SMTP_EHLO:
                   1196:       result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
                   1197:       break;
                   1198: 
                   1199:     case SMTP_HELO:
                   1200:       result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
                   1201:       break;
                   1202: 
                   1203:     case SMTP_STARTTLS:
                   1204:       result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
                   1205:       break;
                   1206: 
                   1207:     case SMTP_AUTH:
                   1208:       result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);
                   1209:       break;
                   1210: 
                   1211:     case SMTP_COMMAND:
                   1212:       result = smtp_state_command_resp(conn, smtpcode, smtpc->state);
                   1213:       break;
                   1214: 
                   1215:     case SMTP_MAIL:
                   1216:       result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
                   1217:       break;
                   1218: 
                   1219:     case SMTP_RCPT:
                   1220:       result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
                   1221:       break;
                   1222: 
                   1223:     case SMTP_DATA:
                   1224:       result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
                   1225:       break;
                   1226: 
                   1227:     case SMTP_POSTDATA:
                   1228:       result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
                   1229:       break;
                   1230: 
                   1231:     case SMTP_QUIT:
                   1232:       /* fallthrough, just stop! */
                   1233:     default:
                   1234:       /* internal error */
                   1235:       state(conn, SMTP_STOP);
                   1236:       break;
                   1237:     }
                   1238:   } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp));
                   1239: 
                   1240:   return result;
                   1241: }
                   1242: 
                   1243: /* Called repeatedly until done from multi.c */
                   1244: static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
                   1245: {
                   1246:   CURLcode result = CURLE_OK;
                   1247:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                   1248: 
                   1249:   if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
                   1250:     result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
                   1251:     if(result || !smtpc->ssldone)
                   1252:       return result;
                   1253:   }
                   1254: 
                   1255:   result = Curl_pp_statemach(&smtpc->pp, FALSE, FALSE);
                   1256:   *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
                   1257: 
                   1258:   return result;
                   1259: }
                   1260: 
                   1261: static CURLcode smtp_block_statemach(struct connectdata *conn,
                   1262:                                      bool disconnecting)
                   1263: {
                   1264:   CURLcode result = CURLE_OK;
                   1265:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                   1266: 
                   1267:   while(smtpc->state != SMTP_STOP && !result)
                   1268:     result = Curl_pp_statemach(&smtpc->pp, TRUE, disconnecting);
                   1269: 
                   1270:   return result;
                   1271: }
                   1272: 
                   1273: /* Allocate and initialize the SMTP struct for the current Curl_easy if
                   1274:    required */
                   1275: static CURLcode smtp_init(struct connectdata *conn)
                   1276: {
                   1277:   CURLcode result = CURLE_OK;
                   1278:   struct Curl_easy *data = conn->data;
                   1279:   struct SMTP *smtp;
                   1280: 
                   1281:   smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
                   1282:   if(!smtp)
                   1283:     result = CURLE_OUT_OF_MEMORY;
                   1284: 
                   1285:   return result;
                   1286: }
                   1287: 
                   1288: /* For the SMTP "protocol connect" and "doing" phases only */
                   1289: static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks)
                   1290: {
                   1291:   return Curl_pp_getsock(&conn->proto.smtpc.pp, socks);
                   1292: }
                   1293: 
                   1294: /***********************************************************************
                   1295:  *
                   1296:  * smtp_connect()
                   1297:  *
                   1298:  * This function should do everything that is to be considered a part of
                   1299:  * the connection phase.
                   1300:  *
                   1301:  * The variable pointed to by 'done' will be TRUE if the protocol-layer
                   1302:  * connect phase is done when this function returns, or FALSE if not.
                   1303:  */
                   1304: static CURLcode smtp_connect(struct connectdata *conn, bool *done)
                   1305: {
                   1306:   CURLcode result = CURLE_OK;
                   1307:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                   1308:   struct pingpong *pp = &smtpc->pp;
                   1309: 
                   1310:   *done = FALSE; /* default to not done yet */
                   1311: 
                   1312:   /* We always support persistent connections in SMTP */
                   1313:   connkeep(conn, "SMTP default");
                   1314: 
                   1315:   /* Set the default response time-out */
                   1316:   pp->response_time = RESP_TIMEOUT;
                   1317:   pp->statemach_act = smtp_statemach_act;
                   1318:   pp->endofresp = smtp_endofresp;
                   1319:   pp->conn = conn;
                   1320: 
                   1321:   /* Initialize the SASL storage */
                   1322:   Curl_sasl_init(&smtpc->sasl, &saslsmtp);
                   1323: 
                   1324:   /* Initialise the pingpong layer */
                   1325:   Curl_pp_init(pp);
                   1326: 
                   1327:   /* Parse the URL options */
                   1328:   result = smtp_parse_url_options(conn);
                   1329:   if(result)
                   1330:     return result;
                   1331: 
                   1332:   /* Parse the URL path */
                   1333:   result = smtp_parse_url_path(conn);
                   1334:   if(result)
                   1335:     return result;
                   1336: 
                   1337:   /* Start off waiting for the server greeting response */
                   1338:   state(conn, SMTP_SERVERGREET);
                   1339: 
                   1340:   result = smtp_multi_statemach(conn, done);
                   1341: 
                   1342:   return result;
                   1343: }
                   1344: 
                   1345: /***********************************************************************
                   1346:  *
                   1347:  * smtp_done()
                   1348:  *
                   1349:  * The DONE function. This does what needs to be done after a single DO has
                   1350:  * performed.
                   1351:  *
                   1352:  * Input argument is already checked for validity.
                   1353:  */
                   1354: static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
                   1355:                           bool premature)
                   1356: {
                   1357:   CURLcode result = CURLE_OK;
                   1358:   struct Curl_easy *data = conn->data;
                   1359:   struct SMTP *smtp = data->req.protop;
                   1360:   struct pingpong *pp = &conn->proto.smtpc.pp;
                   1361:   char *eob;
                   1362:   ssize_t len;
                   1363:   ssize_t bytes_written;
                   1364: 
                   1365:   (void)premature;
                   1366: 
                   1367:   if(!smtp || !pp->conn)
                   1368:     return CURLE_OK;
                   1369: 
                   1370:   /* Cleanup our per-request based variables */
                   1371:   Curl_safefree(smtp->custom);
                   1372: 
                   1373:   if(status) {
                   1374:     connclose(conn, "SMTP done with bad status"); /* marked for closure */
                   1375:     result = status;         /* use the already set error code */
                   1376:   }
                   1377:   else if(!data->set.connect_only && data->set.mail_rcpt &&
                   1378:           (data->set.upload || data->set.mimepost.kind)) {
                   1379:     /* Calculate the EOB taking into account any terminating CRLF from the
                   1380:        previous line of the email or the CRLF of the DATA command when there
                   1381:        is "no mail data". RFC-5321, sect. 4.1.1.4.
                   1382: 
                   1383:        Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to
                   1384:        fail when using a different pointer following a previous write, that
                   1385:        returned CURLE_AGAIN, we duplicate the EOB now rather than when the
                   1386:        bytes written doesn't equal len. */
                   1387:     if(smtp->trailing_crlf || !conn->data->state.infilesize) {
                   1388:       eob = strdup(&SMTP_EOB[2]);
                   1389:       len = SMTP_EOB_LEN - 2;
                   1390:     }
                   1391:     else {
                   1392:       eob = strdup(SMTP_EOB);
                   1393:       len = SMTP_EOB_LEN;
                   1394:     }
                   1395: 
                   1396:     if(!eob)
                   1397:       return CURLE_OUT_OF_MEMORY;
                   1398: 
                   1399:     /* Send the end of block data */
                   1400:     result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
                   1401:     if(result) {
                   1402:       free(eob);
                   1403:       return result;
                   1404:     }
                   1405: 
                   1406:     if(bytes_written != len) {
                   1407:       /* The whole chunk was not sent so keep it around and adjust the
                   1408:          pingpong structure accordingly */
                   1409:       pp->sendthis = eob;
                   1410:       pp->sendsize = len;
                   1411:       pp->sendleft = len - bytes_written;
                   1412:     }
                   1413:     else {
                   1414:       /* Successfully sent so adjust the response timeout relative to now */
                   1415:       pp->response = Curl_now();
                   1416: 
                   1417:       free(eob);
                   1418:     }
                   1419: 
                   1420:     state(conn, SMTP_POSTDATA);
                   1421: 
                   1422:     /* Run the state-machine */
                   1423:     result = smtp_block_statemach(conn, FALSE);
                   1424:   }
                   1425: 
                   1426:   /* Clear the transfer mode for the next request */
                   1427:   smtp->transfer = FTPTRANSFER_BODY;
                   1428: 
                   1429:   return result;
                   1430: }
                   1431: 
                   1432: /***********************************************************************
                   1433:  *
                   1434:  * smtp_perform()
                   1435:  *
                   1436:  * This is the actual DO function for SMTP. Transfer a mail, send a command
                   1437:  * or get some data according to the options previously setup.
                   1438:  */
                   1439: static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
                   1440:                              bool *dophase_done)
                   1441: {
                   1442:   /* This is SMTP and no proxy */
                   1443:   CURLcode result = CURLE_OK;
                   1444:   struct Curl_easy *data = conn->data;
                   1445:   struct SMTP *smtp = data->req.protop;
                   1446: 
                   1447:   DEBUGF(infof(conn->data, "DO phase starts\n"));
                   1448: 
                   1449:   if(data->set.opt_no_body) {
                   1450:     /* Requested no body means no transfer */
                   1451:     smtp->transfer = FTPTRANSFER_INFO;
                   1452:   }
                   1453: 
                   1454:   *dophase_done = FALSE; /* not done yet */
                   1455: 
                   1456:   /* Store the first recipient (or NULL if not specified) */
                   1457:   smtp->rcpt = data->set.mail_rcpt;
                   1458: 
                   1459:   /* Track of whether we've successfully sent at least one RCPT TO command */
                   1460:   smtp->rcpt_had_ok = FALSE;
                   1461: 
                   1462:   /* Track of the last error we've received by sending RCPT TO command */
                   1463:   smtp->rcpt_last_error = 0;
                   1464: 
                   1465:   /* Initial data character is the first character in line: it is implicitly
                   1466:      preceded by a virtual CRLF. */
                   1467:   smtp->trailing_crlf = TRUE;
                   1468:   smtp->eob = 2;
                   1469: 
                   1470:   /* Start the first command in the DO phase */
                   1471:   if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt)
                   1472:     /* MAIL transfer */
                   1473:     result = smtp_perform_mail(conn);
                   1474:   else
                   1475:     /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */
                   1476:     result = smtp_perform_command(conn);
                   1477: 
                   1478:   if(result)
                   1479:     return result;
                   1480: 
                   1481:   /* Run the state-machine */
                   1482:   result = smtp_multi_statemach(conn, dophase_done);
                   1483: 
                   1484:   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
                   1485: 
                   1486:   if(*dophase_done)
                   1487:     DEBUGF(infof(conn->data, "DO phase is complete\n"));
                   1488: 
                   1489:   return result;
                   1490: }
                   1491: 
                   1492: /***********************************************************************
                   1493:  *
                   1494:  * smtp_do()
                   1495:  *
                   1496:  * This function is registered as 'curl_do' function. It decodes the path
                   1497:  * parts etc as a wrapper to the actual DO function (smtp_perform).
                   1498:  *
                   1499:  * The input argument is already checked for validity.
                   1500:  */
                   1501: static CURLcode smtp_do(struct connectdata *conn, bool *done)
                   1502: {
                   1503:   CURLcode result = CURLE_OK;
                   1504: 
                   1505:   *done = FALSE; /* default to false */
                   1506: 
                   1507:   /* Parse the custom request */
                   1508:   result = smtp_parse_custom_request(conn);
                   1509:   if(result)
                   1510:     return result;
                   1511: 
                   1512:   result = smtp_regular_transfer(conn, done);
                   1513: 
                   1514:   return result;
                   1515: }
                   1516: 
                   1517: /***********************************************************************
                   1518:  *
                   1519:  * smtp_disconnect()
                   1520:  *
                   1521:  * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
                   1522:  * resources. BLOCKING.
                   1523:  */
                   1524: static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
                   1525: {
                   1526:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                   1527: 
                   1528:   /* We cannot send quit unconditionally. If this connection is stale or
                   1529:      bad in any way, sending quit and waiting around here will make the
                   1530:      disconnect wait in vain and cause more problems than we need to. */
                   1531: 
                   1532:   /* The SMTP session may or may not have been allocated/setup at this
                   1533:      point! */
                   1534:   if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
                   1535:     if(!smtp_perform_quit(conn))
                   1536:       (void)smtp_block_statemach(conn, TRUE); /* ignore errors on QUIT */
                   1537: 
                   1538:   /* Disconnect from the server */
                   1539:   Curl_pp_disconnect(&smtpc->pp);
                   1540: 
                   1541:   /* Cleanup the SASL module */
                   1542:   Curl_sasl_cleanup(conn, smtpc->sasl.authused);
                   1543: 
                   1544:   /* Cleanup our connection based variables */
                   1545:   Curl_safefree(smtpc->domain);
                   1546: 
                   1547:   return CURLE_OK;
                   1548: }
                   1549: 
                   1550: /* Call this when the DO phase has completed */
                   1551: static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
                   1552: {
                   1553:   struct SMTP *smtp = conn->data->req.protop;
                   1554: 
                   1555:   (void)connected;
                   1556: 
                   1557:   if(smtp->transfer != FTPTRANSFER_BODY)
                   1558:     /* no data to transfer */
                   1559:     Curl_setup_transfer(conn->data, -1, -1, FALSE, -1);
                   1560: 
                   1561:   return CURLE_OK;
                   1562: }
                   1563: 
                   1564: /* Called from multi.c while DOing */
                   1565: static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
                   1566: {
                   1567:   CURLcode result = smtp_multi_statemach(conn, dophase_done);
                   1568: 
                   1569:   if(result)
                   1570:     DEBUGF(infof(conn->data, "DO phase failed\n"));
                   1571:   else if(*dophase_done) {
                   1572:     result = smtp_dophase_done(conn, FALSE /* not connected */);
                   1573: 
                   1574:     DEBUGF(infof(conn->data, "DO phase is complete\n"));
                   1575:   }
                   1576: 
                   1577:   return result;
                   1578: }
                   1579: 
                   1580: /***********************************************************************
                   1581:  *
                   1582:  * smtp_regular_transfer()
                   1583:  *
                   1584:  * The input argument is already checked for validity.
                   1585:  *
                   1586:  * Performs all commands done before a regular transfer between a local and a
                   1587:  * remote host.
                   1588:  */
                   1589: static CURLcode smtp_regular_transfer(struct connectdata *conn,
                   1590:                                       bool *dophase_done)
                   1591: {
                   1592:   CURLcode result = CURLE_OK;
                   1593:   bool connected = FALSE;
                   1594:   struct Curl_easy *data = conn->data;
                   1595: 
                   1596:   /* Make sure size is unknown at this point */
                   1597:   data->req.size = -1;
                   1598: 
                   1599:   /* Set the progress data */
                   1600:   Curl_pgrsSetUploadCounter(data, 0);
                   1601:   Curl_pgrsSetDownloadCounter(data, 0);
                   1602:   Curl_pgrsSetUploadSize(data, -1);
                   1603:   Curl_pgrsSetDownloadSize(data, -1);
                   1604: 
                   1605:   /* Carry out the perform */
                   1606:   result = smtp_perform(conn, &connected, dophase_done);
                   1607: 
                   1608:   /* Perform post DO phase operations if necessary */
                   1609:   if(!result && *dophase_done)
                   1610:     result = smtp_dophase_done(conn, connected);
                   1611: 
                   1612:   return result;
                   1613: }
                   1614: 
                   1615: static CURLcode smtp_setup_connection(struct connectdata *conn)
                   1616: {
                   1617:   CURLcode result;
                   1618: 
                   1619:   /* Clear the TLS upgraded flag */
                   1620:   conn->tls_upgraded = FALSE;
                   1621: 
                   1622:   /* Initialise the SMTP layer */
                   1623:   result = smtp_init(conn);
                   1624:   if(result)
                   1625:     return result;
                   1626: 
                   1627:   return CURLE_OK;
                   1628: }
                   1629: 
                   1630: /***********************************************************************
                   1631:  *
                   1632:  * smtp_parse_url_options()
                   1633:  *
                   1634:  * Parse the URL login options.
                   1635:  */
                   1636: static CURLcode smtp_parse_url_options(struct connectdata *conn)
                   1637: {
                   1638:   CURLcode result = CURLE_OK;
                   1639:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                   1640:   const char *ptr = conn->options;
                   1641: 
                   1642:   smtpc->sasl.resetprefs = TRUE;
                   1643: 
                   1644:   while(!result && ptr && *ptr) {
                   1645:     const char *key = ptr;
                   1646:     const char *value;
                   1647: 
                   1648:     while(*ptr && *ptr != '=')
                   1649:       ptr++;
                   1650: 
                   1651:     value = ptr + 1;
                   1652: 
                   1653:     while(*ptr && *ptr != ';')
                   1654:       ptr++;
                   1655: 
                   1656:     if(strncasecompare(key, "AUTH=", 5))
                   1657:       result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
                   1658:                                                value, ptr - value);
                   1659:     else
                   1660:       result = CURLE_URL_MALFORMAT;
                   1661: 
                   1662:     if(*ptr == ';')
                   1663:       ptr++;
                   1664:   }
                   1665: 
                   1666:   return result;
                   1667: }
                   1668: 
                   1669: /***********************************************************************
                   1670:  *
                   1671:  * smtp_parse_url_path()
                   1672:  *
                   1673:  * Parse the URL path into separate path components.
                   1674:  */
                   1675: static CURLcode smtp_parse_url_path(struct connectdata *conn)
                   1676: {
                   1677:   /* The SMTP struct is already initialised in smtp_connect() */
                   1678:   struct Curl_easy *data = conn->data;
                   1679:   struct smtp_conn *smtpc = &conn->proto.smtpc;
                   1680:   const char *path = &data->state.up.path[1]; /* skip leading path */
                   1681:   char localhost[HOSTNAME_MAX + 1];
                   1682: 
                   1683:   /* Calculate the path if necessary */
                   1684:   if(!*path) {
                   1685:     if(!Curl_gethostname(localhost, sizeof(localhost)))
                   1686:       path = localhost;
                   1687:     else
                   1688:       path = "localhost";
                   1689:   }
                   1690: 
                   1691:   /* URL decode the path and use it as the domain in our EHLO */
                   1692:   return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
                   1693: }
                   1694: 
                   1695: /***********************************************************************
                   1696:  *
                   1697:  * smtp_parse_custom_request()
                   1698:  *
                   1699:  * Parse the custom request.
                   1700:  */
                   1701: static CURLcode smtp_parse_custom_request(struct connectdata *conn)
                   1702: {
                   1703:   CURLcode result = CURLE_OK;
                   1704:   struct Curl_easy *data = conn->data;
                   1705:   struct SMTP *smtp = data->req.protop;
                   1706:   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
                   1707: 
                   1708:   /* URL decode the custom request */
                   1709:   if(custom)
                   1710:     result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE);
                   1711: 
                   1712:   return result;
                   1713: }
                   1714: 
                   1715: /***********************************************************************
                   1716:  *
                   1717:  * smtp_parse_address()
                   1718:  *
                   1719:  * Parse the fully qualified mailbox address into a local address part and the
                   1720:  * host name, converting the host name to an IDN A-label, as per RFC-5890, if
                   1721:  * necessary.
                   1722:  *
                   1723:  * Parameters:
                   1724:  *
                   1725:  * conn  [in]              - The connection handle.
                   1726:  * fqma  [in]              - The fully qualified mailbox address (which may or
                   1727:  *                           may not contain UTF-8 characters).
                   1728:  * address        [in/out] - A new allocated buffer which holds the local
                   1729:  *                           address part of the mailbox. This buffer must be
                   1730:  *                           free'ed by the caller.
                   1731:  * host           [in/out] - The host name structure that holds the original,
                   1732:  *                           and optionally encoded, host name.
                   1733:  *                           Curl_free_idnconverted_hostname() must be called
                   1734:  *                           once the caller has finished with the structure.
                   1735:  *
                   1736:  * Returns CURLE_OK on success.
                   1737:  *
                   1738:  * Notes:
                   1739:  *
                   1740:  * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor
                   1741:  * that conversion then we shall return success. This allow the caller to send
                   1742:  * the data to the server as a U-label (as per RFC-6531 sect. 3.2).
                   1743:  *
                   1744:  * If an mailbox '@' separator cannot be located then the mailbox is considered
                   1745:  * to be either a local mailbox or an invalid mailbox (depending on what the
                   1746:  * calling function deems it to be) then the input will simply be returned in
                   1747:  * the address part with the host name being NULL.
                   1748:  */
                   1749: static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
                   1750:                                    char **address, struct hostname *host)
                   1751: {
                   1752:   CURLcode result = CURLE_OK;
                   1753:   size_t length;
                   1754: 
                   1755:   /* Duplicate the fully qualified email address so we can manipulate it,
                   1756:      ensuring it doesn't contain the delimiters if specified */
                   1757:   char *dup = strdup(fqma[0] == '<' ? fqma + 1  : fqma);
                   1758:   if(!dup)
                   1759:     return CURLE_OUT_OF_MEMORY;
                   1760: 
                   1761:   length = strlen(dup);
                   1762:   if(dup[length - 1] == '>')
                   1763:     dup[length - 1] = '\0';
                   1764: 
                   1765:   /* Extract the host name from the address (if we can) */
                   1766:   host->name = strpbrk(dup, "@");
                   1767:   if(host->name) {
                   1768:     *host->name = '\0';
                   1769:     host->name = host->name + 1;
                   1770: 
                   1771:     /* Attempt to convert the host name to IDN ACE */
                   1772:     (void) Curl_idnconvert_hostname(conn, host);
                   1773: 
                   1774:     /* If Curl_idnconvert_hostname() fails then we shall attempt to continue
                   1775:        and send the host name using UTF-8 rather than as 7-bit ACE (which is
                   1776:        our preference) */
                   1777:   }
                   1778: 
                   1779:   /* Extract the local address from the mailbox */
                   1780:   *address = dup;
                   1781: 
                   1782:   return result;
                   1783: }
                   1784: 
                   1785: CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
                   1786: {
                   1787:   /* When sending a SMTP payload we must detect CRLF. sequences making sure
                   1788:      they are sent as CRLF.. instead, as a . on the beginning of a line will
                   1789:      be deleted by the server when not part of an EOB terminator and a
                   1790:      genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
                   1791:      data by the server
                   1792:   */
                   1793:   ssize_t i;
                   1794:   ssize_t si;
                   1795:   struct Curl_easy *data = conn->data;
                   1796:   struct SMTP *smtp = data->req.protop;
                   1797:   char *scratch = data->state.scratch;
                   1798:   char *newscratch = NULL;
                   1799:   char *oldscratch = NULL;
                   1800:   size_t eob_sent;
                   1801: 
                   1802:   /* Do we need to allocate a scratch buffer? */
                   1803:   if(!scratch || data->set.crlf) {
                   1804:     oldscratch = scratch;
                   1805: 
                   1806:     scratch = newscratch = malloc(2 * data->set.upload_buffer_size);
                   1807:     if(!newscratch) {
                   1808:       failf(data, "Failed to alloc scratch buffer!");
                   1809: 
                   1810:       return CURLE_OUT_OF_MEMORY;
                   1811:     }
                   1812:   }
                   1813:   DEBUGASSERT(data->set.upload_buffer_size >= (size_t)nread);
                   1814: 
                   1815:   /* Have we already sent part of the EOB? */
                   1816:   eob_sent = smtp->eob;
                   1817: 
                   1818:   /* This loop can be improved by some kind of Boyer-Moore style of
                   1819:      approach but that is saved for later... */
                   1820:   for(i = 0, si = 0; i < nread; i++) {
                   1821:     if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
                   1822:       smtp->eob++;
                   1823: 
                   1824:       /* Is the EOB potentially the terminating CRLF? */
                   1825:       if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
                   1826:         smtp->trailing_crlf = TRUE;
                   1827:       else
                   1828:         smtp->trailing_crlf = FALSE;
                   1829:     }
                   1830:     else if(smtp->eob) {
                   1831:       /* A previous substring matched so output that first */
                   1832:       memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
                   1833:       si += smtp->eob - eob_sent;
                   1834: 
                   1835:       /* Then compare the first byte */
                   1836:       if(SMTP_EOB[0] == data->req.upload_fromhere[i])
                   1837:         smtp->eob = 1;
                   1838:       else
                   1839:         smtp->eob = 0;
                   1840: 
                   1841:       eob_sent = 0;
                   1842: 
                   1843:       /* Reset the trailing CRLF flag as there was more data */
                   1844:       smtp->trailing_crlf = FALSE;
                   1845:     }
                   1846: 
                   1847:     /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
                   1848:     if(SMTP_EOB_FIND_LEN == smtp->eob) {
                   1849:       /* Copy the replacement data to the target buffer */
                   1850:       memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent],
                   1851:              SMTP_EOB_REPL_LEN - eob_sent);
                   1852:       si += SMTP_EOB_REPL_LEN - eob_sent;
                   1853:       smtp->eob = 0;
                   1854:       eob_sent = 0;
                   1855:     }
                   1856:     else if(!smtp->eob)
                   1857:       scratch[si++] = data->req.upload_fromhere[i];
                   1858:   }
                   1859: 
                   1860:   if(smtp->eob - eob_sent) {
                   1861:     /* A substring matched before processing ended so output that now */
                   1862:     memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
                   1863:     si += smtp->eob - eob_sent;
                   1864:   }
                   1865: 
                   1866:   /* Only use the new buffer if we replaced something */
                   1867:   if(si != nread) {
                   1868:     /* Upload from the new (replaced) buffer instead */
                   1869:     data->req.upload_fromhere = scratch;
                   1870: 
                   1871:     /* Save the buffer so it can be freed later */
                   1872:     data->state.scratch = scratch;
                   1873: 
                   1874:     /* Free the old scratch buffer */
                   1875:     free(oldscratch);
                   1876: 
                   1877:     /* Set the new amount too */
                   1878:     data->req.upload_present = si;
                   1879:   }
                   1880:   else
                   1881:     free(newscratch);
                   1882: 
                   1883:   return CURLE_OK;
                   1884: }
                   1885: 
                   1886: #endif /* CURL_DISABLE_SMTP */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>