Annotation of embedaddon/curl/lib/pop3.c, revision 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>