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

1.1       misho       1: /***************************************************************************
                      2:  *                                  _   _ ____  _
                      3:  *  Project                     ___| | | |  _ \| |
                      4:  *                             / __| | | | |_) | |
                      5:  *                            | (__| |_| |  _ <| |___
                      6:  *                             \___|\___/|_| \_\_____|
                      7:  *
                      8:  * Copyright (C) 1998 - 2019, 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:  * RFC1734 POP3 Authentication
                     22:  * RFC1939 POP3 protocol
                     23:  * RFC2195 CRAM-MD5 authentication
                     24:  * RFC2384 POP URL Scheme
                     25:  * RFC2449 POP3 Extension Mechanism
                     26:  * RFC2595 Using TLS with IMAP, POP3 and ACAP
                     27:  * RFC2831 DIGEST-MD5 authentication
                     28:  * RFC4422 Simple Authentication and Security Layer (SASL)
                     29:  * RFC4616 PLAIN authentication
                     30:  * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
                     31:  * RFC5034 POP3 SASL Authentication Mechanism
                     32:  * RFC6749 OAuth 2.0 Authorization Framework
                     33:  * RFC8314 Use of TLS for Email Submission and Access
                     34:  * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
                     35:  *
                     36:  ***************************************************************************/
                     37: 
                     38: #include "curl_setup.h"
                     39: 
                     40: #ifndef CURL_DISABLE_POP3
                     41: 
                     42: #ifdef HAVE_NETINET_IN_H
                     43: #include <netinet/in.h>
                     44: #endif
                     45: #ifdef HAVE_ARPA_INET_H
                     46: #include <arpa/inet.h>
                     47: #endif
                     48: #ifdef HAVE_UTSNAME_H
                     49: #include <sys/utsname.h>
                     50: #endif
                     51: #ifdef HAVE_NETDB_H
                     52: #include <netdb.h>
                     53: #endif
                     54: #ifdef __VMS
                     55: #include <in.h>
                     56: #include <inet.h>
                     57: #endif
                     58: 
                     59: #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
                     60: #undef in_addr_t
                     61: #define in_addr_t unsigned long
                     62: #endif
                     63: 
                     64: #include <curl/curl.h>
                     65: #include "urldata.h"
                     66: #include "sendf.h"
                     67: #include "hostip.h"
                     68: #include "progress.h"
                     69: #include "transfer.h"
                     70: #include "escape.h"
                     71: #include "http.h" /* for HTTP proxy tunnel stuff */
                     72: #include "socks.h"
                     73: #include "pop3.h"
                     74: #include "strtoofft.h"
                     75: #include "strcase.h"
                     76: #include "vtls/vtls.h"
                     77: #include "connect.h"
                     78: #include "strerror.h"
                     79: #include "select.h"
                     80: #include "multiif.h"
                     81: #include "url.h"
                     82: #include "curl_sasl.h"
                     83: #include "curl_md5.h"
                     84: #include "warnless.h"
                     85: /* The last 3 #include files should be in this order */
                     86: #include "curl_printf.h"
                     87: #include "curl_memory.h"
                     88: #include "memdebug.h"
                     89: 
                     90: /* Local API functions */
                     91: static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
                     92: static CURLcode pop3_do(struct connectdata *conn, bool *done);
                     93: static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
                     94:                           bool premature);
                     95: static CURLcode pop3_connect(struct connectdata *conn, bool *done);
                     96: static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
                     97: static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
                     98: static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks);
                     99: static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
                    100: static CURLcode pop3_setup_connection(struct connectdata *conn);
                    101: static CURLcode pop3_parse_url_options(struct connectdata *conn);
                    102: static CURLcode pop3_parse_url_path(struct connectdata *conn);
                    103: static CURLcode pop3_parse_custom_request(struct connectdata *conn);
                    104: static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech,
                    105:                                   const char *initresp);
                    106: static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp);
                    107: static void pop3_get_message(char *buffer, char **outptr);
                    108: 
                    109: /*
                    110:  * POP3 protocol handler.
                    111:  */
                    112: 
                    113: const struct Curl_handler Curl_handler_pop3 = {
                    114:   "POP3",                           /* scheme */
                    115:   pop3_setup_connection,            /* setup_connection */
                    116:   pop3_do,                          /* do_it */
                    117:   pop3_done,                        /* done */
                    118:   ZERO_NULL,                        /* do_more */
                    119:   pop3_connect,                     /* connect_it */
                    120:   pop3_multi_statemach,             /* connecting */
                    121:   pop3_doing,                       /* doing */
                    122:   pop3_getsock,                     /* proto_getsock */
                    123:   pop3_getsock,                     /* doing_getsock */
                    124:   ZERO_NULL,                        /* domore_getsock */
                    125:   ZERO_NULL,                        /* perform_getsock */
                    126:   pop3_disconnect,                  /* disconnect */
                    127:   ZERO_NULL,                        /* readwrite */
                    128:   ZERO_NULL,                        /* connection_check */
                    129:   PORT_POP3,                        /* defport */
                    130:   CURLPROTO_POP3,                   /* protocol */
                    131:   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
                    132:   PROTOPT_URLOPTIONS
                    133: };
                    134: 
                    135: #ifdef USE_SSL
                    136: /*
                    137:  * POP3S protocol handler.
                    138:  */
                    139: 
                    140: const struct Curl_handler Curl_handler_pop3s = {
                    141:   "POP3S",                          /* scheme */
                    142:   pop3_setup_connection,            /* setup_connection */
                    143:   pop3_do,                          /* do_it */
                    144:   pop3_done,                        /* done */
                    145:   ZERO_NULL,                        /* do_more */
                    146:   pop3_connect,                     /* connect_it */
                    147:   pop3_multi_statemach,             /* connecting */
                    148:   pop3_doing,                       /* doing */
                    149:   pop3_getsock,                     /* proto_getsock */
                    150:   pop3_getsock,                     /* doing_getsock */
                    151:   ZERO_NULL,                        /* domore_getsock */
                    152:   ZERO_NULL,                        /* perform_getsock */
                    153:   pop3_disconnect,                  /* disconnect */
                    154:   ZERO_NULL,                        /* readwrite */
                    155:   ZERO_NULL,                        /* connection_check */
                    156:   PORT_POP3S,                       /* defport */
                    157:   CURLPROTO_POP3S,                  /* protocol */
                    158:   PROTOPT_CLOSEACTION | PROTOPT_SSL
                    159:   | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
                    160: };
                    161: #endif
                    162: 
                    163: /* SASL parameters for the pop3 protocol */
                    164: static const struct SASLproto saslpop3 = {
                    165:   "pop",                      /* The service name */
                    166:   '*',                        /* Code received when continuation is expected */
                    167:   '+',                        /* Code to receive upon authentication success */
                    168:   255 - 8,                    /* Maximum initial response length (no max) */
                    169:   pop3_perform_auth,          /* Send authentication command */
                    170:   pop3_continue_auth,         /* Send authentication continuation */
                    171:   pop3_get_message            /* Get SASL response message */
                    172: };
                    173: 
                    174: #ifdef USE_SSL
                    175: static void pop3_to_pop3s(struct connectdata *conn)
                    176: {
                    177:   /* Change the connection handler */
                    178:   conn->handler = &Curl_handler_pop3s;
                    179: 
                    180:   /* Set the connection's upgraded to TLS flag */
                    181:   conn->tls_upgraded = TRUE;
                    182: }
                    183: #else
                    184: #define pop3_to_pop3s(x) Curl_nop_stmt
                    185: #endif
                    186: 
                    187: /***********************************************************************
                    188:  *
                    189:  * pop3_endofresp()
                    190:  *
                    191:  * Checks for an ending POP3 status code at the start of the given string, but
                    192:  * also detects the APOP timestamp from the server greeting and various
                    193:  * capabilities from the CAPA response including the supported authentication
                    194:  * types and allowed SASL mechanisms.
                    195:  */
                    196: static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
                    197:                            int *resp)
                    198: {
                    199:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    200: 
                    201:   /* Do we have an error response? */
                    202:   if(len >= 4 && !memcmp("-ERR", line, 4)) {
                    203:     *resp = '-';
                    204: 
                    205:     return TRUE;
                    206:   }
                    207: 
                    208:   /* Are we processing CAPA command responses? */
                    209:   if(pop3c->state == POP3_CAPA) {
                    210:     /* Do we have the terminating line? */
                    211:     if(len >= 1 && line[0] == '.')
                    212:       /* Treat the response as a success */
                    213:       *resp = '+';
                    214:     else
                    215:       /* Treat the response as an untagged continuation */
                    216:       *resp = '*';
                    217: 
                    218:     return TRUE;
                    219:   }
                    220: 
                    221:   /* Do we have a success response? */
                    222:   if(len >= 3 && !memcmp("+OK", line, 3)) {
                    223:     *resp = '+';
                    224: 
                    225:     return TRUE;
                    226:   }
                    227: 
                    228:   /* Do we have a continuation response? */
                    229:   if(len >= 1 && line[0] == '+') {
                    230:     *resp = '*';
                    231: 
                    232:     return TRUE;
                    233:   }
                    234: 
                    235:   return FALSE; /* Nothing for us */
                    236: }
                    237: 
                    238: /***********************************************************************
                    239:  *
                    240:  * pop3_get_message()
                    241:  *
                    242:  * Gets the authentication message from the response buffer.
                    243:  */
                    244: static void pop3_get_message(char *buffer, char **outptr)
                    245: {
                    246:   size_t len = strlen(buffer);
                    247:   char *message = NULL;
                    248: 
                    249:   if(len > 2) {
                    250:     /* Find the start of the message */
                    251:     len -= 2;
                    252:     for(message = buffer + 2; *message == ' ' || *message == '\t';
                    253:         message++, len--)
                    254:       ;
                    255: 
                    256:     /* Find the end of the message */
                    257:     for(; len--;)
                    258:       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
                    259:          message[len] != '\t')
                    260:         break;
                    261: 
                    262:     /* Terminate the message */
                    263:     if(++len) {
                    264:       message[len] = '\0';
                    265:     }
                    266:   }
                    267:   else
                    268:     /* junk input => zero length output */
                    269:     message = &buffer[len];
                    270: 
                    271:   *outptr = message;
                    272: }
                    273: 
                    274: /***********************************************************************
                    275:  *
                    276:  * state()
                    277:  *
                    278:  * This is the ONLY way to change POP3 state!
                    279:  */
                    280: static void state(struct connectdata *conn, pop3state newstate)
                    281: {
                    282:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    283: #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
                    284:   /* for debug purposes */
                    285:   static const char * const names[] = {
                    286:     "STOP",
                    287:     "SERVERGREET",
                    288:     "CAPA",
                    289:     "STARTTLS",
                    290:     "UPGRADETLS",
                    291:     "AUTH",
                    292:     "APOP",
                    293:     "USER",
                    294:     "PASS",
                    295:     "COMMAND",
                    296:     "QUIT",
                    297:     /* LAST */
                    298:   };
                    299: 
                    300:   if(pop3c->state != newstate)
                    301:     infof(conn->data, "POP3 %p state change from %s to %s\n",
                    302:           (void *)pop3c, names[pop3c->state], names[newstate]);
                    303: #endif
                    304: 
                    305:   pop3c->state = newstate;
                    306: }
                    307: 
                    308: /***********************************************************************
                    309:  *
                    310:  * pop3_perform_capa()
                    311:  *
                    312:  * Sends the CAPA command in order to obtain a list of server side supported
                    313:  * capabilities.
                    314:  */
                    315: static CURLcode pop3_perform_capa(struct connectdata *conn)
                    316: {
                    317:   CURLcode result = CURLE_OK;
                    318:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    319: 
                    320:   pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
                    321:   pop3c->sasl.authused = SASL_AUTH_NONE;  /* Clear the auth. mechanism used */
                    322:   pop3c->tls_supported = FALSE;           /* Clear the TLS capability */
                    323: 
                    324:   /* Send the CAPA command */
                    325:   result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA");
                    326: 
                    327:   if(!result)
                    328:     state(conn, POP3_CAPA);
                    329: 
                    330:   return result;
                    331: }
                    332: 
                    333: /***********************************************************************
                    334:  *
                    335:  * pop3_perform_starttls()
                    336:  *
                    337:  * Sends the STLS command to start the upgrade to TLS.
                    338:  */
                    339: static CURLcode pop3_perform_starttls(struct connectdata *conn)
                    340: {
                    341:   /* Send the STLS command */
                    342:   CURLcode result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS");
                    343: 
                    344:   if(!result)
                    345:     state(conn, POP3_STARTTLS);
                    346: 
                    347:   return result;
                    348: }
                    349: 
                    350: /***********************************************************************
                    351:  *
                    352:  * pop3_perform_upgrade_tls()
                    353:  *
                    354:  * Performs the upgrade to TLS.
                    355:  */
                    356: static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
                    357: {
                    358:   /* Start the SSL connection */
                    359:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    360:   CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
                    361:                                                  &pop3c->ssldone);
                    362: 
                    363:   if(!result) {
                    364:     if(pop3c->state != POP3_UPGRADETLS)
                    365:       state(conn, POP3_UPGRADETLS);
                    366: 
                    367:     if(pop3c->ssldone) {
                    368:       pop3_to_pop3s(conn);
                    369:       result = pop3_perform_capa(conn);
                    370:     }
                    371:   }
                    372: 
                    373:   return result;
                    374: }
                    375: 
                    376: /***********************************************************************
                    377:  *
                    378:  * pop3_perform_user()
                    379:  *
                    380:  * Sends a clear text USER command to authenticate with.
                    381:  */
                    382: static CURLcode pop3_perform_user(struct connectdata *conn)
                    383: {
                    384:   CURLcode result = CURLE_OK;
                    385: 
                    386:   /* Check we have a username and password to authenticate with and end the
                    387:      connect phase if we don't */
                    388:   if(!conn->bits.user_passwd) {
                    389:     state(conn, POP3_STOP);
                    390: 
                    391:     return result;
                    392:   }
                    393: 
                    394:   /* Send the USER command */
                    395:   result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
                    396:                          conn->user ? conn->user : "");
                    397:   if(!result)
                    398:     state(conn, POP3_USER);
                    399: 
                    400:   return result;
                    401: }
                    402: 
                    403: #ifndef CURL_DISABLE_CRYPTO_AUTH
                    404: /***********************************************************************
                    405:  *
                    406:  * pop3_perform_apop()
                    407:  *
                    408:  * Sends an APOP command to authenticate with.
                    409:  */
                    410: static CURLcode pop3_perform_apop(struct connectdata *conn)
                    411: {
                    412:   CURLcode result = CURLE_OK;
                    413:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    414:   size_t i;
                    415:   MD5_context *ctxt;
                    416:   unsigned char digest[MD5_DIGEST_LEN];
                    417:   char secret[2 * MD5_DIGEST_LEN + 1];
                    418: 
                    419:   /* Check we have a username and password to authenticate with and end the
                    420:      connect phase if we don't */
                    421:   if(!conn->bits.user_passwd) {
                    422:     state(conn, POP3_STOP);
                    423: 
                    424:     return result;
                    425:   }
                    426: 
                    427:   /* Create the digest */
                    428:   ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
                    429:   if(!ctxt)
                    430:     return CURLE_OUT_OF_MEMORY;
                    431: 
                    432:   Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
                    433:                   curlx_uztoui(strlen(pop3c->apoptimestamp)));
                    434: 
                    435:   Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
                    436:                   curlx_uztoui(strlen(conn->passwd)));
                    437: 
                    438:   /* Finalise the digest */
                    439:   Curl_MD5_final(ctxt, digest);
                    440: 
                    441:   /* Convert the calculated 16 octet digest into a 32 byte hex string */
                    442:   for(i = 0; i < MD5_DIGEST_LEN; i++)
                    443:     msnprintf(&secret[2 * i], 3, "%02x", digest[i]);
                    444: 
                    445:   result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
                    446: 
                    447:   if(!result)
                    448:     state(conn, POP3_APOP);
                    449: 
                    450:   return result;
                    451: }
                    452: #endif
                    453: 
                    454: /***********************************************************************
                    455:  *
                    456:  * pop3_perform_auth()
                    457:  *
                    458:  * Sends an AUTH command allowing the client to login with the given SASL
                    459:  * authentication mechanism.
                    460:  */
                    461: static CURLcode pop3_perform_auth(struct connectdata *conn,
                    462:                                   const char *mech,
                    463:                                   const char *initresp)
                    464: {
                    465:   CURLcode result = CURLE_OK;
                    466:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    467: 
                    468:   if(initresp) {                                  /* AUTH <mech> ...<crlf> */
                    469:     /* Send the AUTH command with the initial response */
                    470:     result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
                    471:   }
                    472:   else {
                    473:     /* Send the AUTH command */
                    474:     result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
                    475:   }
                    476: 
                    477:   return result;
                    478: }
                    479: 
                    480: /***********************************************************************
                    481:  *
                    482:  * pop3_continue_auth()
                    483:  *
                    484:  * Sends SASL continuation data or cancellation.
                    485:  */
                    486: static CURLcode pop3_continue_auth(struct connectdata *conn,
                    487:                                    const char *resp)
                    488: {
                    489:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    490: 
                    491:   return Curl_pp_sendf(&pop3c->pp, "%s", resp);
                    492: }
                    493: 
                    494: /***********************************************************************
                    495:  *
                    496:  * pop3_perform_authentication()
                    497:  *
                    498:  * Initiates the authentication sequence, with the appropriate SASL
                    499:  * authentication mechanism, falling back to APOP and clear text should a
                    500:  * common mechanism not be available between the client and server.
                    501:  */
                    502: static CURLcode pop3_perform_authentication(struct connectdata *conn)
                    503: {
                    504:   CURLcode result = CURLE_OK;
                    505:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    506:   saslprogress progress = SASL_IDLE;
                    507: 
                    508:   /* Check we have enough data to authenticate with and end the
                    509:      connect phase if we don't */
                    510:   if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) {
                    511:     state(conn, POP3_STOP);
                    512:     return result;
                    513:   }
                    514: 
                    515:   if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
                    516:     /* Calculate the SASL login details */
                    517:     result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress);
                    518: 
                    519:     if(!result)
                    520:       if(progress == SASL_INPROGRESS)
                    521:         state(conn, POP3_AUTH);
                    522:   }
                    523: 
                    524:   if(!result && progress == SASL_IDLE) {
                    525: #ifndef CURL_DISABLE_CRYPTO_AUTH
                    526:     if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
                    527:       /* Perform APOP authentication */
                    528:       result = pop3_perform_apop(conn);
                    529:     else
                    530: #endif
                    531:     if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
                    532:       /* Perform clear text authentication */
                    533:       result = pop3_perform_user(conn);
                    534:     else {
                    535:       /* Other mechanisms not supported */
                    536:       infof(conn->data, "No known authentication mechanisms supported!\n");
                    537:       result = CURLE_LOGIN_DENIED;
                    538:     }
                    539:   }
                    540: 
                    541:   return result;
                    542: }
                    543: 
                    544: /***********************************************************************
                    545:  *
                    546:  * pop3_perform_command()
                    547:  *
                    548:  * Sends a POP3 based command.
                    549:  */
                    550: static CURLcode pop3_perform_command(struct connectdata *conn)
                    551: {
                    552:   CURLcode result = CURLE_OK;
                    553:   struct Curl_easy *data = conn->data;
                    554:   struct POP3 *pop3 = data->req.protop;
                    555:   const char *command = NULL;
                    556: 
                    557:   /* Calculate the default command */
                    558:   if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
                    559:     command = "LIST";
                    560: 
                    561:     if(pop3->id[0] != '\0')
                    562:       /* Message specific LIST so skip the BODY transfer */
                    563:       pop3->transfer = FTPTRANSFER_INFO;
                    564:   }
                    565:   else
                    566:     command = "RETR";
                    567: 
                    568:   /* Send the command */
                    569:   if(pop3->id[0] != '\0')
                    570:     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
                    571:                            (pop3->custom && pop3->custom[0] != '\0' ?
                    572:                             pop3->custom : command), pop3->id);
                    573:   else
                    574:     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s",
                    575:                            (pop3->custom && pop3->custom[0] != '\0' ?
                    576:                             pop3->custom : command));
                    577: 
                    578:   if(!result)
                    579:     state(conn, POP3_COMMAND);
                    580: 
                    581:   return result;
                    582: }
                    583: 
                    584: /***********************************************************************
                    585:  *
                    586:  * pop3_perform_quit()
                    587:  *
                    588:  * Performs the quit action prior to sclose() be called.
                    589:  */
                    590: static CURLcode pop3_perform_quit(struct connectdata *conn)
                    591: {
                    592:   /* Send the QUIT command */
                    593:   CURLcode result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT");
                    594: 
                    595:   if(!result)
                    596:     state(conn, POP3_QUIT);
                    597: 
                    598:   return result;
                    599: }
                    600: 
                    601: /* For the initial server greeting */
                    602: static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
                    603:                                             int pop3code,
                    604:                                             pop3state instate)
                    605: {
                    606:   CURLcode result = CURLE_OK;
                    607:   struct Curl_easy *data = conn->data;
                    608:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    609:   const char *line = data->state.buffer;
                    610:   size_t len = strlen(line);
                    611: 
                    612:   (void)instate; /* no use for this yet */
                    613: 
                    614:   if(pop3code != '+') {
                    615:     failf(data, "Got unexpected pop3-server response");
                    616:     result = CURLE_WEIRD_SERVER_REPLY;
                    617:   }
                    618:   else {
                    619:     /* Does the server support APOP authentication? */
                    620:     if(len >= 4 && line[len - 2] == '>') {
                    621:       /* Look for the APOP timestamp */
                    622:       size_t i;
                    623:       for(i = 3; i < len - 2; ++i) {
                    624:         if(line[i] == '<') {
                    625:           /* Calculate the length of the timestamp */
                    626:           size_t timestamplen = len - 1 - i;
                    627:           char *at;
                    628:           if(!timestamplen)
                    629:             break;
                    630: 
                    631:           /* Allocate some memory for the timestamp */
                    632:           pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
                    633: 
                    634:           if(!pop3c->apoptimestamp)
                    635:             break;
                    636: 
                    637:           /* Copy the timestamp */
                    638:           memcpy(pop3c->apoptimestamp, line + i, timestamplen);
                    639:           pop3c->apoptimestamp[timestamplen] = '\0';
                    640: 
                    641:           /* If the timestamp does not contain '@' it is not (as required by
                    642:              RFC-1939) conformant to the RFC-822 message id syntax, and we
                    643:              therefore do not use APOP authentication. */
                    644:           at = strchr(pop3c->apoptimestamp, '@');
                    645:           if(!at)
                    646:             Curl_safefree(pop3c->apoptimestamp);
                    647:           else
                    648:             /* Store the APOP capability */
                    649:             pop3c->authtypes |= POP3_TYPE_APOP;
                    650:           break;
                    651:         }
                    652:       }
                    653:     }
                    654: 
                    655:     result = pop3_perform_capa(conn);
                    656:   }
                    657: 
                    658:   return result;
                    659: }
                    660: 
                    661: /* For CAPA responses */
                    662: static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
                    663:                                      pop3state instate)
                    664: {
                    665:   CURLcode result = CURLE_OK;
                    666:   struct Curl_easy *data = conn->data;
                    667:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    668:   const char *line = data->state.buffer;
                    669:   size_t len = strlen(line);
                    670: 
                    671:   (void)instate; /* no use for this yet */
                    672: 
                    673:   /* Do we have a untagged continuation response? */
                    674:   if(pop3code == '*') {
                    675:     /* Does the server support the STLS capability? */
                    676:     if(len >= 4 && !memcmp(line, "STLS", 4))
                    677:       pop3c->tls_supported = TRUE;
                    678: 
                    679:     /* Does the server support clear text authentication? */
                    680:     else if(len >= 4 && !memcmp(line, "USER", 4))
                    681:       pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
                    682: 
                    683:     /* Does the server support SASL based authentication? */
                    684:     else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
                    685:       pop3c->authtypes |= POP3_TYPE_SASL;
                    686: 
                    687:       /* Advance past the SASL keyword */
                    688:       line += 5;
                    689:       len -= 5;
                    690: 
                    691:       /* Loop through the data line */
                    692:       for(;;) {
                    693:         size_t llen;
                    694:         size_t wordlen;
                    695:         unsigned int mechbit;
                    696: 
                    697:         while(len &&
                    698:               (*line == ' ' || *line == '\t' ||
                    699:                *line == '\r' || *line == '\n')) {
                    700: 
                    701:           line++;
                    702:           len--;
                    703:         }
                    704: 
                    705:         if(!len)
                    706:           break;
                    707: 
                    708:         /* Extract the word */
                    709:         for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
                    710:               line[wordlen] != '\t' && line[wordlen] != '\r' &&
                    711:               line[wordlen] != '\n';)
                    712:           wordlen++;
                    713: 
                    714:         /* Test the word for a matching authentication mechanism */
                    715:         mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
                    716:         if(mechbit && llen == wordlen)
                    717:           pop3c->sasl.authmechs |= mechbit;
                    718: 
                    719:         line += wordlen;
                    720:         len -= wordlen;
                    721:       }
                    722:     }
                    723:   }
                    724:   else if(pop3code == '+') {
                    725:     if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
                    726:       /* We don't have a SSL/TLS connection yet, but SSL is requested */
                    727:       if(pop3c->tls_supported)
                    728:         /* Switch to TLS connection now */
                    729:         result = pop3_perform_starttls(conn);
                    730:       else if(data->set.use_ssl == CURLUSESSL_TRY)
                    731:         /* Fallback and carry on with authentication */
                    732:         result = pop3_perform_authentication(conn);
                    733:       else {
                    734:         failf(data, "STLS not supported.");
                    735:         result = CURLE_USE_SSL_FAILED;
                    736:       }
                    737:     }
                    738:     else
                    739:       result = pop3_perform_authentication(conn);
                    740:   }
                    741:   else {
                    742:     /* Clear text is supported when CAPA isn't recognised */
                    743:     pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
                    744: 
                    745:     result = pop3_perform_authentication(conn);
                    746:   }
                    747: 
                    748:   return result;
                    749: }
                    750: 
                    751: /* For STARTTLS responses */
                    752: static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
                    753:                                          int pop3code,
                    754:                                          pop3state instate)
                    755: {
                    756:   CURLcode result = CURLE_OK;
                    757:   struct Curl_easy *data = conn->data;
                    758: 
                    759:   (void)instate; /* no use for this yet */
                    760: 
                    761:   if(pop3code != '+') {
                    762:     if(data->set.use_ssl != CURLUSESSL_TRY) {
                    763:       failf(data, "STARTTLS denied");
                    764:       result = CURLE_USE_SSL_FAILED;
                    765:     }
                    766:     else
                    767:       result = pop3_perform_authentication(conn);
                    768:   }
                    769:   else
                    770:     result = pop3_perform_upgrade_tls(conn);
                    771: 
                    772:   return result;
                    773: }
                    774: 
                    775: /* For SASL authentication responses */
                    776: static CURLcode pop3_state_auth_resp(struct connectdata *conn,
                    777:                                      int pop3code,
                    778:                                      pop3state instate)
                    779: {
                    780:   CURLcode result = CURLE_OK;
                    781:   struct Curl_easy *data = conn->data;
                    782:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    783:   saslprogress progress;
                    784: 
                    785:   (void)instate; /* no use for this yet */
                    786: 
                    787:   result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress);
                    788:   if(!result)
                    789:     switch(progress) {
                    790:     case SASL_DONE:
                    791:       state(conn, POP3_STOP);  /* Authenticated */
                    792:       break;
                    793:     case SASL_IDLE:            /* No mechanism left after cancellation */
                    794: #ifndef CURL_DISABLE_CRYPTO_AUTH
                    795:       if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
                    796:         /* Perform APOP authentication */
                    797:         result = pop3_perform_apop(conn);
                    798:       else
                    799: #endif
                    800:       if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
                    801:         /* Perform clear text authentication */
                    802:         result = pop3_perform_user(conn);
                    803:       else {
                    804:         failf(data, "Authentication cancelled");
                    805:         result = CURLE_LOGIN_DENIED;
                    806:       }
                    807:       break;
                    808:     default:
                    809:       break;
                    810:     }
                    811: 
                    812:   return result;
                    813: }
                    814: 
                    815: #ifndef CURL_DISABLE_CRYPTO_AUTH
                    816: /* For APOP responses */
                    817: static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
                    818:                                      pop3state instate)
                    819: {
                    820:   CURLcode result = CURLE_OK;
                    821:   struct Curl_easy *data = conn->data;
                    822: 
                    823:   (void)instate; /* no use for this yet */
                    824: 
                    825:   if(pop3code != '+') {
                    826:     failf(data, "Authentication failed: %d", pop3code);
                    827:     result = CURLE_LOGIN_DENIED;
                    828:   }
                    829:   else
                    830:     /* End of connect phase */
                    831:     state(conn, POP3_STOP);
                    832: 
                    833:   return result;
                    834: }
                    835: #endif
                    836: 
                    837: /* For USER responses */
                    838: static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
                    839:                                      pop3state instate)
                    840: {
                    841:   CURLcode result = CURLE_OK;
                    842:   struct Curl_easy *data = conn->data;
                    843: 
                    844:   (void)instate; /* no use for this yet */
                    845: 
                    846:   if(pop3code != '+') {
                    847:     failf(data, "Access denied. %c", pop3code);
                    848:     result = CURLE_LOGIN_DENIED;
                    849:   }
                    850:   else
                    851:     /* Send the PASS command */
                    852:     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
                    853:                            conn->passwd ? conn->passwd : "");
                    854:   if(!result)
                    855:     state(conn, POP3_PASS);
                    856: 
                    857:   return result;
                    858: }
                    859: 
                    860: /* For PASS responses */
                    861: static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
                    862:                                      pop3state instate)
                    863: {
                    864:   CURLcode result = CURLE_OK;
                    865:   struct Curl_easy *data = conn->data;
                    866: 
                    867:   (void)instate; /* no use for this yet */
                    868: 
                    869:   if(pop3code != '+') {
                    870:     failf(data, "Access denied. %c", pop3code);
                    871:     result = CURLE_LOGIN_DENIED;
                    872:   }
                    873:   else
                    874:     /* End of connect phase */
                    875:     state(conn, POP3_STOP);
                    876: 
                    877:   return result;
                    878: }
                    879: 
                    880: /* For command responses */
                    881: static CURLcode pop3_state_command_resp(struct connectdata *conn,
                    882:                                         int pop3code,
                    883:                                         pop3state instate)
                    884: {
                    885:   CURLcode result = CURLE_OK;
                    886:   struct Curl_easy *data = conn->data;
                    887:   struct POP3 *pop3 = data->req.protop;
                    888:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    889:   struct pingpong *pp = &pop3c->pp;
                    890: 
                    891:   (void)instate; /* no use for this yet */
                    892: 
                    893:   if(pop3code != '+') {
                    894:     state(conn, POP3_STOP);
                    895:     return CURLE_RECV_ERROR;
                    896:   }
                    897: 
                    898:   /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
                    899:      EOB string so count this is two matching bytes. This is necessary to make
                    900:      the code detect the EOB if the only data than comes now is %2e CR LF like
                    901:      when there is no body to return. */
                    902:   pop3c->eob = 2;
                    903: 
                    904:   /* But since this initial CR LF pair is not part of the actual body, we set
                    905:      the strip counter here so that these bytes won't be delivered. */
                    906:   pop3c->strip = 2;
                    907: 
                    908:   if(pop3->transfer == FTPTRANSFER_BODY) {
                    909:     /* POP3 download */
                    910:     Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
                    911: 
                    912:     if(pp->cache) {
                    913:       /* The header "cache" contains a bunch of data that is actually body
                    914:          content so send it as such. Note that there may even be additional
                    915:          "headers" after the body */
                    916: 
                    917:       if(!data->set.opt_no_body) {
                    918:         result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
                    919:         if(result)
                    920:           return result;
                    921:       }
                    922: 
                    923:       /* Free the cache */
                    924:       Curl_safefree(pp->cache);
                    925: 
                    926:       /* Reset the cache size */
                    927:       pp->cache_size = 0;
                    928:     }
                    929:   }
                    930: 
                    931:   /* End of DO phase */
                    932:   state(conn, POP3_STOP);
                    933: 
                    934:   return result;
                    935: }
                    936: 
                    937: static CURLcode pop3_statemach_act(struct connectdata *conn)
                    938: {
                    939:   CURLcode result = CURLE_OK;
                    940:   curl_socket_t sock = conn->sock[FIRSTSOCKET];
                    941:   int pop3code;
                    942:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                    943:   struct pingpong *pp = &pop3c->pp;
                    944:   size_t nread = 0;
                    945: 
                    946:   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
                    947:   if(pop3c->state == POP3_UPGRADETLS)
                    948:     return pop3_perform_upgrade_tls(conn);
                    949: 
                    950:   /* Flush any data that needs to be sent */
                    951:   if(pp->sendleft)
                    952:     return Curl_pp_flushsend(pp);
                    953: 
                    954:  do {
                    955:     /* Read the response from the server */
                    956:     result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
                    957:     if(result)
                    958:       return result;
                    959: 
                    960:     if(!pop3code)
                    961:       break;
                    962: 
                    963:     /* We have now received a full POP3 server response */
                    964:     switch(pop3c->state) {
                    965:     case POP3_SERVERGREET:
                    966:       result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
                    967:       break;
                    968: 
                    969:     case POP3_CAPA:
                    970:       result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
                    971:       break;
                    972: 
                    973:     case POP3_STARTTLS:
                    974:       result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
                    975:       break;
                    976: 
                    977:     case POP3_AUTH:
                    978:       result = pop3_state_auth_resp(conn, pop3code, pop3c->state);
                    979:       break;
                    980: 
                    981: #ifndef CURL_DISABLE_CRYPTO_AUTH
                    982:     case POP3_APOP:
                    983:       result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
                    984:       break;
                    985: #endif
                    986: 
                    987:     case POP3_USER:
                    988:       result = pop3_state_user_resp(conn, pop3code, pop3c->state);
                    989:       break;
                    990: 
                    991:     case POP3_PASS:
                    992:       result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
                    993:       break;
                    994: 
                    995:     case POP3_COMMAND:
                    996:       result = pop3_state_command_resp(conn, pop3code, pop3c->state);
                    997:       break;
                    998: 
                    999:     case POP3_QUIT:
                   1000:       /* fallthrough, just stop! */
                   1001:     default:
                   1002:       /* internal error */
                   1003:       state(conn, POP3_STOP);
                   1004:       break;
                   1005:     }
                   1006:   } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
                   1007: 
                   1008:   return result;
                   1009: }
                   1010: 
                   1011: /* Called repeatedly until done from multi.c */
                   1012: static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
                   1013: {
                   1014:   CURLcode result = CURLE_OK;
                   1015:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                   1016: 
                   1017:   if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
                   1018:     result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
                   1019:     if(result || !pop3c->ssldone)
                   1020:       return result;
                   1021:   }
                   1022: 
                   1023:   result = Curl_pp_statemach(&pop3c->pp, FALSE, FALSE);
                   1024:   *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
                   1025: 
                   1026:   return result;
                   1027: }
                   1028: 
                   1029: static CURLcode pop3_block_statemach(struct connectdata *conn,
                   1030:                                      bool disconnecting)
                   1031: {
                   1032:   CURLcode result = CURLE_OK;
                   1033:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                   1034: 
                   1035:   while(pop3c->state != POP3_STOP && !result)
                   1036:     result = Curl_pp_statemach(&pop3c->pp, TRUE, disconnecting);
                   1037: 
                   1038:   return result;
                   1039: }
                   1040: 
                   1041: /* Allocate and initialize the POP3 struct for the current Curl_easy if
                   1042:    required */
                   1043: static CURLcode pop3_init(struct connectdata *conn)
                   1044: {
                   1045:   CURLcode result = CURLE_OK;
                   1046:   struct Curl_easy *data = conn->data;
                   1047:   struct POP3 *pop3;
                   1048: 
                   1049:   pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
                   1050:   if(!pop3)
                   1051:     result = CURLE_OUT_OF_MEMORY;
                   1052: 
                   1053:   return result;
                   1054: }
                   1055: 
                   1056: /* For the POP3 "protocol connect" and "doing" phases only */
                   1057: static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks)
                   1058: {
                   1059:   return Curl_pp_getsock(&conn->proto.pop3c.pp, socks);
                   1060: }
                   1061: 
                   1062: /***********************************************************************
                   1063:  *
                   1064:  * pop3_connect()
                   1065:  *
                   1066:  * This function should do everything that is to be considered a part of the
                   1067:  * connection phase.
                   1068:  *
                   1069:  * The variable 'done' points to will be TRUE if the protocol-layer connect
                   1070:  * phase is done when this function returns, or FALSE if not.
                   1071:  */
                   1072: static CURLcode pop3_connect(struct connectdata *conn, bool *done)
                   1073: {
                   1074:   CURLcode result = CURLE_OK;
                   1075:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                   1076:   struct pingpong *pp = &pop3c->pp;
                   1077: 
                   1078:   *done = FALSE; /* default to not done yet */
                   1079: 
                   1080:   /* We always support persistent connections in POP3 */
                   1081:   connkeep(conn, "POP3 default");
                   1082: 
                   1083:   /* Set the default response time-out */
                   1084:   pp->response_time = RESP_TIMEOUT;
                   1085:   pp->statemach_act = pop3_statemach_act;
                   1086:   pp->endofresp = pop3_endofresp;
                   1087:   pp->conn = conn;
                   1088: 
                   1089:   /* Set the default preferred authentication type and mechanism */
                   1090:   pop3c->preftype = POP3_TYPE_ANY;
                   1091:   Curl_sasl_init(&pop3c->sasl, &saslpop3);
                   1092: 
                   1093:   /* Initialise the pingpong layer */
                   1094:   Curl_pp_init(pp);
                   1095: 
                   1096:   /* Parse the URL options */
                   1097:   result = pop3_parse_url_options(conn);
                   1098:   if(result)
                   1099:     return result;
                   1100: 
                   1101:   /* Start off waiting for the server greeting response */
                   1102:   state(conn, POP3_SERVERGREET);
                   1103: 
                   1104:   result = pop3_multi_statemach(conn, done);
                   1105: 
                   1106:   return result;
                   1107: }
                   1108: 
                   1109: /***********************************************************************
                   1110:  *
                   1111:  * pop3_done()
                   1112:  *
                   1113:  * The DONE function. This does what needs to be done after a single DO has
                   1114:  * performed.
                   1115:  *
                   1116:  * Input argument is already checked for validity.
                   1117:  */
                   1118: static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
                   1119:                           bool premature)
                   1120: {
                   1121:   CURLcode result = CURLE_OK;
                   1122:   struct Curl_easy *data = conn->data;
                   1123:   struct POP3 *pop3 = data->req.protop;
                   1124: 
                   1125:   (void)premature;
                   1126: 
                   1127:   if(!pop3)
                   1128:     return CURLE_OK;
                   1129: 
                   1130:   if(status) {
                   1131:     connclose(conn, "POP3 done with bad status");
                   1132:     result = status;         /* use the already set error code */
                   1133:   }
                   1134: 
                   1135:   /* Cleanup our per-request based variables */
                   1136:   Curl_safefree(pop3->id);
                   1137:   Curl_safefree(pop3->custom);
                   1138: 
                   1139:   /* Clear the transfer mode for the next request */
                   1140:   pop3->transfer = FTPTRANSFER_BODY;
                   1141: 
                   1142:   return result;
                   1143: }
                   1144: 
                   1145: /***********************************************************************
                   1146:  *
                   1147:  * pop3_perform()
                   1148:  *
                   1149:  * This is the actual DO function for POP3. Get a message/listing according to
                   1150:  * the options previously setup.
                   1151:  */
                   1152: static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
                   1153:                              bool *dophase_done)
                   1154: {
                   1155:   /* This is POP3 and no proxy */
                   1156:   CURLcode result = CURLE_OK;
                   1157:   struct POP3 *pop3 = conn->data->req.protop;
                   1158: 
                   1159:   DEBUGF(infof(conn->data, "DO phase starts\n"));
                   1160: 
                   1161:   if(conn->data->set.opt_no_body) {
                   1162:     /* Requested no body means no transfer */
                   1163:     pop3->transfer = FTPTRANSFER_INFO;
                   1164:   }
                   1165: 
                   1166:   *dophase_done = FALSE; /* not done yet */
                   1167: 
                   1168:   /* Start the first command in the DO phase */
                   1169:   result = pop3_perform_command(conn);
                   1170:   if(result)
                   1171:     return result;
                   1172: 
                   1173:   /* Run the state-machine */
                   1174:   result = pop3_multi_statemach(conn, dophase_done);
                   1175: 
                   1176:   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
                   1177: 
                   1178:   if(*dophase_done)
                   1179:     DEBUGF(infof(conn->data, "DO phase is complete\n"));
                   1180: 
                   1181:   return result;
                   1182: }
                   1183: 
                   1184: /***********************************************************************
                   1185:  *
                   1186:  * pop3_do()
                   1187:  *
                   1188:  * This function is registered as 'curl_do' function. It decodes the path
                   1189:  * parts etc as a wrapper to the actual DO function (pop3_perform).
                   1190:  *
                   1191:  * The input argument is already checked for validity.
                   1192:  */
                   1193: static CURLcode pop3_do(struct connectdata *conn, bool *done)
                   1194: {
                   1195:   CURLcode result = CURLE_OK;
                   1196: 
                   1197:   *done = FALSE; /* default to false */
                   1198: 
                   1199:   /* Parse the URL path */
                   1200:   result = pop3_parse_url_path(conn);
                   1201:   if(result)
                   1202:     return result;
                   1203: 
                   1204:   /* Parse the custom request */
                   1205:   result = pop3_parse_custom_request(conn);
                   1206:   if(result)
                   1207:     return result;
                   1208: 
                   1209:   result = pop3_regular_transfer(conn, done);
                   1210: 
                   1211:   return result;
                   1212: }
                   1213: 
                   1214: /***********************************************************************
                   1215:  *
                   1216:  * pop3_disconnect()
                   1217:  *
                   1218:  * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
                   1219:  * resources. BLOCKING.
                   1220:  */
                   1221: static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
                   1222: {
                   1223:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                   1224: 
                   1225:   /* We cannot send quit unconditionally. If this connection is stale or
                   1226:      bad in any way, sending quit and waiting around here will make the
                   1227:      disconnect wait in vain and cause more problems than we need to. */
                   1228: 
                   1229:   /* The POP3 session may or may not have been allocated/setup at this
                   1230:      point! */
                   1231:   if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
                   1232:     if(!pop3_perform_quit(conn))
                   1233:       (void)pop3_block_statemach(conn, TRUE); /* ignore errors on QUIT */
                   1234: 
                   1235:   /* Disconnect from the server */
                   1236:   Curl_pp_disconnect(&pop3c->pp);
                   1237: 
                   1238:   /* Cleanup the SASL module */
                   1239:   Curl_sasl_cleanup(conn, pop3c->sasl.authused);
                   1240: 
                   1241:   /* Cleanup our connection based variables */
                   1242:   Curl_safefree(pop3c->apoptimestamp);
                   1243: 
                   1244:   return CURLE_OK;
                   1245: }
                   1246: 
                   1247: /* Call this when the DO phase has completed */
                   1248: static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
                   1249: {
                   1250:   (void)conn;
                   1251:   (void)connected;
                   1252: 
                   1253:   return CURLE_OK;
                   1254: }
                   1255: 
                   1256: /* Called from multi.c while DOing */
                   1257: static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
                   1258: {
                   1259:   CURLcode result = pop3_multi_statemach(conn, dophase_done);
                   1260: 
                   1261:   if(result)
                   1262:     DEBUGF(infof(conn->data, "DO phase failed\n"));
                   1263:   else if(*dophase_done) {
                   1264:     result = pop3_dophase_done(conn, FALSE /* not connected */);
                   1265: 
                   1266:     DEBUGF(infof(conn->data, "DO phase is complete\n"));
                   1267:   }
                   1268: 
                   1269:   return result;
                   1270: }
                   1271: 
                   1272: /***********************************************************************
                   1273:  *
                   1274:  * pop3_regular_transfer()
                   1275:  *
                   1276:  * The input argument is already checked for validity.
                   1277:  *
                   1278:  * Performs all commands done before a regular transfer between a local and a
                   1279:  * remote host.
                   1280:  */
                   1281: static CURLcode pop3_regular_transfer(struct connectdata *conn,
                   1282:                                       bool *dophase_done)
                   1283: {
                   1284:   CURLcode result = CURLE_OK;
                   1285:   bool connected = FALSE;
                   1286:   struct Curl_easy *data = conn->data;
                   1287: 
                   1288:   /* Make sure size is unknown at this point */
                   1289:   data->req.size = -1;
                   1290: 
                   1291:   /* Set the progress data */
                   1292:   Curl_pgrsSetUploadCounter(data, 0);
                   1293:   Curl_pgrsSetDownloadCounter(data, 0);
                   1294:   Curl_pgrsSetUploadSize(data, -1);
                   1295:   Curl_pgrsSetDownloadSize(data, -1);
                   1296: 
                   1297:   /* Carry out the perform */
                   1298:   result = pop3_perform(conn, &connected, dophase_done);
                   1299: 
                   1300:   /* Perform post DO phase operations if necessary */
                   1301:   if(!result && *dophase_done)
                   1302:     result = pop3_dophase_done(conn, connected);
                   1303: 
                   1304:   return result;
                   1305: }
                   1306: 
                   1307: static CURLcode pop3_setup_connection(struct connectdata *conn)
                   1308: {
                   1309:   /* Initialise the POP3 layer */
                   1310:   CURLcode result = pop3_init(conn);
                   1311:   if(result)
                   1312:     return result;
                   1313: 
                   1314:   /* Clear the TLS upgraded flag */
                   1315:   conn->tls_upgraded = FALSE;
                   1316: 
                   1317:   return CURLE_OK;
                   1318: }
                   1319: 
                   1320: /***********************************************************************
                   1321:  *
                   1322:  * pop3_parse_url_options()
                   1323:  *
                   1324:  * Parse the URL login options.
                   1325:  */
                   1326: static CURLcode pop3_parse_url_options(struct connectdata *conn)
                   1327: {
                   1328:   CURLcode result = CURLE_OK;
                   1329:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                   1330:   const char *ptr = conn->options;
                   1331: 
                   1332:   pop3c->sasl.resetprefs = TRUE;
                   1333: 
                   1334:   while(!result && ptr && *ptr) {
                   1335:     const char *key = ptr;
                   1336:     const char *value;
                   1337: 
                   1338:     while(*ptr && *ptr != '=')
                   1339:         ptr++;
                   1340: 
                   1341:     value = ptr + 1;
                   1342: 
                   1343:     while(*ptr && *ptr != ';')
                   1344:       ptr++;
                   1345: 
                   1346:     if(strncasecompare(key, "AUTH=", 5)) {
                   1347:       result = Curl_sasl_parse_url_auth_option(&pop3c->sasl,
                   1348:                                                value, ptr - value);
                   1349: 
                   1350:       if(result && strncasecompare(value, "+APOP", ptr - value)) {
                   1351:         pop3c->preftype = POP3_TYPE_APOP;
                   1352:         pop3c->sasl.prefmech = SASL_AUTH_NONE;
                   1353:         result = CURLE_OK;
                   1354:       }
                   1355:     }
                   1356:     else
                   1357:       result = CURLE_URL_MALFORMAT;
                   1358: 
                   1359:     if(*ptr == ';')
                   1360:       ptr++;
                   1361:   }
                   1362: 
                   1363:   if(pop3c->preftype != POP3_TYPE_APOP)
                   1364:     switch(pop3c->sasl.prefmech) {
                   1365:     case SASL_AUTH_NONE:
                   1366:       pop3c->preftype = POP3_TYPE_NONE;
                   1367:       break;
                   1368:     case SASL_AUTH_DEFAULT:
                   1369:       pop3c->preftype = POP3_TYPE_ANY;
                   1370:       break;
                   1371:     default:
                   1372:       pop3c->preftype = POP3_TYPE_SASL;
                   1373:       break;
                   1374:     }
                   1375: 
                   1376:   return result;
                   1377: }
                   1378: 
                   1379: /***********************************************************************
                   1380:  *
                   1381:  * pop3_parse_url_path()
                   1382:  *
                   1383:  * Parse the URL path into separate path components.
                   1384:  */
                   1385: static CURLcode pop3_parse_url_path(struct connectdata *conn)
                   1386: {
                   1387:   /* The POP3 struct is already initialised in pop3_connect() */
                   1388:   struct Curl_easy *data = conn->data;
                   1389:   struct POP3 *pop3 = data->req.protop;
                   1390:   const char *path = &data->state.up.path[1]; /* skip leading path */
                   1391: 
                   1392:   /* URL decode the path for the message ID */
                   1393:   return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
                   1394: }
                   1395: 
                   1396: /***********************************************************************
                   1397:  *
                   1398:  * pop3_parse_custom_request()
                   1399:  *
                   1400:  * Parse the custom request.
                   1401:  */
                   1402: static CURLcode pop3_parse_custom_request(struct connectdata *conn)
                   1403: {
                   1404:   CURLcode result = CURLE_OK;
                   1405:   struct Curl_easy *data = conn->data;
                   1406:   struct POP3 *pop3 = data->req.protop;
                   1407:   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
                   1408: 
                   1409:   /* URL decode the custom request */
                   1410:   if(custom)
                   1411:     result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
                   1412: 
                   1413:   return result;
                   1414: }
                   1415: 
                   1416: /***********************************************************************
                   1417:  *
                   1418:  * Curl_pop3_write()
                   1419:  *
                   1420:  * This function scans the body after the end-of-body and writes everything
                   1421:  * until the end is found.
                   1422:  */
                   1423: CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
                   1424: {
                   1425:   /* This code could be made into a special function in the handler struct */
                   1426:   CURLcode result = CURLE_OK;
                   1427:   struct Curl_easy *data = conn->data;
                   1428:   struct SingleRequest *k = &data->req;
                   1429: 
                   1430:   struct pop3_conn *pop3c = &conn->proto.pop3c;
                   1431:   bool strip_dot = FALSE;
                   1432:   size_t last = 0;
                   1433:   size_t i;
                   1434: 
                   1435:   /* Search through the buffer looking for the end-of-body marker which is
                   1436:      5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
                   1437:      the eob so the server will have prefixed it with an extra dot which we
                   1438:      need to strip out. Additionally the marker could of course be spread out
                   1439:      over 5 different data chunks. */
                   1440:   for(i = 0; i < nread; i++) {
                   1441:     size_t prev = pop3c->eob;
                   1442: 
                   1443:     switch(str[i]) {
                   1444:     case 0x0d:
                   1445:       if(pop3c->eob == 0) {
                   1446:         pop3c->eob++;
                   1447: 
                   1448:         if(i) {
                   1449:           /* Write out the body part that didn't match */
                   1450:           result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
                   1451:                                      i - last);
                   1452: 
                   1453:           if(result)
                   1454:             return result;
                   1455: 
                   1456:           last = i;
                   1457:         }
                   1458:       }
                   1459:       else if(pop3c->eob == 3)
                   1460:         pop3c->eob++;
                   1461:       else
                   1462:         /* If the character match wasn't at position 0 or 3 then restart the
                   1463:            pattern matching */
                   1464:         pop3c->eob = 1;
                   1465:       break;
                   1466: 
                   1467:     case 0x0a:
                   1468:       if(pop3c->eob == 1 || pop3c->eob == 4)
                   1469:         pop3c->eob++;
                   1470:       else
                   1471:         /* If the character match wasn't at position 1 or 4 then start the
                   1472:            search again */
                   1473:         pop3c->eob = 0;
                   1474:       break;
                   1475: 
                   1476:     case 0x2e:
                   1477:       if(pop3c->eob == 2)
                   1478:         pop3c->eob++;
                   1479:       else if(pop3c->eob == 3) {
                   1480:         /* We have an extra dot after the CRLF which we need to strip off */
                   1481:         strip_dot = TRUE;
                   1482:         pop3c->eob = 0;
                   1483:       }
                   1484:       else
                   1485:         /* If the character match wasn't at position 2 then start the search
                   1486:            again */
                   1487:         pop3c->eob = 0;
                   1488:       break;
                   1489: 
                   1490:     default:
                   1491:       pop3c->eob = 0;
                   1492:       break;
                   1493:     }
                   1494: 
                   1495:     /* Did we have a partial match which has subsequently failed? */
                   1496:     if(prev && prev >= pop3c->eob) {
                   1497:       /* Strip can only be non-zero for the very first mismatch after CRLF
                   1498:          and then both prev and strip are equal and nothing will be output
                   1499:          below */
                   1500:       while(prev && pop3c->strip) {
                   1501:         prev--;
                   1502:         pop3c->strip--;
                   1503:       }
                   1504: 
                   1505:       if(prev) {
                   1506:         /* If the partial match was the CRLF and dot then only write the CRLF
                   1507:            as the server would have inserted the dot */
                   1508:         result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB,
                   1509:                                    strip_dot ? prev - 1 : prev);
                   1510: 
                   1511:         if(result)
                   1512:           return result;
                   1513: 
                   1514:         last = i;
                   1515:         strip_dot = FALSE;
                   1516:       }
                   1517:     }
                   1518:   }
                   1519: 
                   1520:   if(pop3c->eob == POP3_EOB_LEN) {
                   1521:     /* We have a full match so the transfer is done, however we must transfer
                   1522:     the CRLF at the start of the EOB as this is considered to be part of the
                   1523:     message as per RFC-1939, sect. 3 */
                   1524:     result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
                   1525: 
                   1526:     k->keepon &= ~KEEP_RECV;
                   1527:     pop3c->eob = 0;
                   1528: 
                   1529:     return result;
                   1530:   }
                   1531: 
                   1532:   if(pop3c->eob)
                   1533:     /* While EOB is matching nothing should be output */
                   1534:     return CURLE_OK;
                   1535: 
                   1536:   if(nread - last) {
                   1537:     result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
                   1538:                                nread - last);
                   1539:   }
                   1540: 
                   1541:   return result;
                   1542: }
                   1543: 
                   1544: #endif /* CURL_DISABLE_POP3 */

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