1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel (at) 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 * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt> 34 * 35 ***************************************************************************/ 36 37 #include "curl_setup.h" 38 39 #ifndef CURL_DISABLE_POP3 40 41 #ifdef HAVE_NETINET_IN_H 42 #include <netinet/in.h> 43 #endif 44 #ifdef HAVE_ARPA_INET_H 45 #include <arpa/inet.h> 46 #endif 47 #ifdef HAVE_UTSNAME_H 48 #include <sys/utsname.h> 49 #endif 50 #ifdef HAVE_NETDB_H 51 #include <netdb.h> 52 #endif 53 #ifdef __VMS 54 #include <in.h> 55 #include <inet.h> 56 #endif 57 58 #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) 59 #undef in_addr_t 60 #define in_addr_t unsigned long 61 #endif 62 63 #include <curl/curl.h> 64 #include "urldata.h" 65 #include "sendf.h" 66 #include "hostip.h" 67 #include "progress.h" 68 #include "transfer.h" 69 #include "escape.h" 70 #include "http.h" /* for HTTP proxy tunnel stuff */ 71 #include "socks.h" 72 #include "pop3.h" 73 #include "strtoofft.h" 74 #include "strcase.h" 75 #include "vtls/vtls.h" 76 #include "connect.h" 77 #include "strerror.h" 78 #include "select.h" 79 #include "multiif.h" 80 #include "url.h" 81 #include "curl_sasl.h" 82 #include "curl_md5.h" 83 #include "warnless.h" 84 /* The last 3 #include files should be in this order */ 85 #include "curl_printf.h" 86 #include "curl_memory.h" 87 #include "memdebug.h" 88 89 /* Local API functions */ 90 static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done); 91 static CURLcode pop3_do(struct connectdata *conn, bool *done); 92 static CURLcode pop3_done(struct connectdata *conn, CURLcode status, 93 bool premature); 94 static CURLcode pop3_connect(struct connectdata *conn, bool *done); 95 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead); 96 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done); 97 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, 98 int numsocks); 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 && !memcmp(line, ".", 1)) 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 && !memcmp("+", line, 1)) { 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 CURLcode result = CURLE_OK; 342 343 /* Send the STLS command */ 344 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS"); 345 346 if(!result) 347 state(conn, POP3_STARTTLS); 348 349 return result; 350 } 351 352 /*********************************************************************** 353 * 354 * pop3_perform_upgrade_tls() 355 * 356 * Performs the upgrade to TLS. 357 */ 358 static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn) 359 { 360 CURLcode result = CURLE_OK; 361 struct pop3_conn *pop3c = &conn->proto.pop3c; 362 363 /* Start the SSL connection */ 364 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone); 365 366 if(!result) { 367 if(pop3c->state != POP3_UPGRADETLS) 368 state(conn, POP3_UPGRADETLS); 369 370 if(pop3c->ssldone) { 371 pop3_to_pop3s(conn); 372 result = pop3_perform_capa(conn); 373 } 374 } 375 376 return result; 377 } 378 379 /*********************************************************************** 380 * 381 * pop3_perform_user() 382 * 383 * Sends a clear text USER command to authenticate with. 384 */ 385 static CURLcode pop3_perform_user(struct connectdata *conn) 386 { 387 CURLcode result = CURLE_OK; 388 389 /* Check we have a username and password to authenticate with and end the 390 connect phase if we don't */ 391 if(!conn->bits.user_passwd) { 392 state(conn, POP3_STOP); 393 394 return result; 395 } 396 397 /* Send the USER command */ 398 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s", 399 conn->user ? conn->user : ""); 400 if(!result) 401 state(conn, POP3_USER); 402 403 return result; 404 } 405 406 #ifndef CURL_DISABLE_CRYPTO_AUTH 407 /*********************************************************************** 408 * 409 * pop3_perform_apop() 410 * 411 * Sends an APOP command to authenticate with. 412 */ 413 static CURLcode pop3_perform_apop(struct connectdata *conn) 414 { 415 CURLcode result = CURLE_OK; 416 struct pop3_conn *pop3c = &conn->proto.pop3c; 417 size_t i; 418 MD5_context *ctxt; 419 unsigned char digest[MD5_DIGEST_LEN]; 420 char secret[2 * MD5_DIGEST_LEN + 1]; 421 422 /* Check we have a username and password to authenticate with and end the 423 connect phase if we don't */ 424 if(!conn->bits.user_passwd) { 425 state(conn, POP3_STOP); 426 427 return result; 428 } 429 430 /* Create the digest */ 431 ctxt = Curl_MD5_init(Curl_DIGEST_MD5); 432 if(!ctxt) 433 return CURLE_OUT_OF_MEMORY; 434 435 Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp, 436 curlx_uztoui(strlen(pop3c->apoptimestamp))); 437 438 Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd, 439 curlx_uztoui(strlen(conn->passwd))); 440 441 /* Finalise the digest */ 442 Curl_MD5_final(ctxt, digest); 443 444 /* Convert the calculated 16 octet digest into a 32 byte hex string */ 445 for(i = 0; i < MD5_DIGEST_LEN; i++) 446 snprintf(&secret[2 * i], 3, "%02x", digest[i]); 447 448 result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret); 449 450 if(!result) 451 state(conn, POP3_APOP); 452 453 return result; 454 } 455 #endif 456 457 /*********************************************************************** 458 * 459 * pop3_perform_auth() 460 * 461 * Sends an AUTH command allowing the client to login with the given SASL 462 * authentication mechanism. 463 */ 464 static CURLcode pop3_perform_auth(struct connectdata *conn, 465 const char *mech, 466 const char *initresp) 467 { 468 CURLcode result = CURLE_OK; 469 struct pop3_conn *pop3c = &conn->proto.pop3c; 470 471 if(initresp) { /* AUTH <mech> ...<crlf> */ 472 /* Send the AUTH command with the initial response */ 473 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp); 474 } 475 else { 476 /* Send the AUTH command */ 477 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); 478 } 479 480 return result; 481 } 482 483 /*********************************************************************** 484 * 485 * pop3_continue_auth() 486 * 487 * Sends SASL continuation data or cancellation. 488 */ 489 static CURLcode pop3_continue_auth(struct connectdata *conn, 490 const char *resp) 491 { 492 struct pop3_conn *pop3c = &conn->proto.pop3c; 493 494 return Curl_pp_sendf(&pop3c->pp, "%s", resp); 495 } 496 497 /*********************************************************************** 498 * 499 * pop3_perform_authentication() 500 * 501 * Initiates the authentication sequence, with the appropriate SASL 502 * authentication mechanism, falling back to APOP and clear text should a 503 * common mechanism not be available between the client and server. 504 */ 505 static CURLcode pop3_perform_authentication(struct connectdata *conn) 506 { 507 CURLcode result = CURLE_OK; 508 struct pop3_conn *pop3c = &conn->proto.pop3c; 509 saslprogress progress = SASL_IDLE; 510 511 /* Check we have enough data to authenticate with and end the 512 connect phase if we don't */ 513 if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) { 514 state(conn, POP3_STOP); 515 return result; 516 } 517 518 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { 519 /* Calculate the SASL login details */ 520 result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress); 521 522 if(!result) 523 if(progress == SASL_INPROGRESS) 524 state(conn, POP3_AUTH); 525 } 526 527 if(!result && progress == SASL_IDLE) { 528 #ifndef CURL_DISABLE_CRYPTO_AUTH 529 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) 530 /* Perform APOP authentication */ 531 result = pop3_perform_apop(conn); 532 else 533 #endif 534 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) 535 /* Perform clear text authentication */ 536 result = pop3_perform_user(conn); 537 else { 538 /* Other mechanisms not supported */ 539 infof(conn->data, "No known authentication mechanisms supported!\n"); 540 result = CURLE_LOGIN_DENIED; 541 } 542 } 543 544 return result; 545 } 546 547 /*********************************************************************** 548 * 549 * pop3_perform_command() 550 * 551 * Sends a POP3 based command. 552 */ 553 static CURLcode pop3_perform_command(struct connectdata *conn) 554 { 555 CURLcode result = CURLE_OK; 556 struct Curl_easy *data = conn->data; 557 struct POP3 *pop3 = data->req.protop; 558 const char *command = NULL; 559 560 /* Calculate the default command */ 561 if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) { 562 command = "LIST"; 563 564 if(pop3->id[0] != '\0') 565 /* Message specific LIST so skip the BODY transfer */ 566 pop3->transfer = FTPTRANSFER_INFO; 567 } 568 else 569 command = "RETR"; 570 571 /* Send the command */ 572 if(pop3->id[0] != '\0') 573 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s", 574 (pop3->custom && pop3->custom[0] != '\0' ? 575 pop3->custom : command), pop3->id); 576 else 577 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", 578 (pop3->custom && pop3->custom[0] != '\0' ? 579 pop3->custom : command)); 580 581 if(!result) 582 state(conn, POP3_COMMAND); 583 584 return result; 585 } 586 587 /*********************************************************************** 588 * 589 * pop3_perform_quit() 590 * 591 * Performs the quit action prior to sclose() be called. 592 */ 593 static CURLcode pop3_perform_quit(struct connectdata *conn) 594 { 595 CURLcode result = CURLE_OK; 596 597 /* Send the QUIT command */ 598 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT"); 599 600 if(!result) 601 state(conn, POP3_QUIT); 602 603 return result; 604 } 605 606 /* For the initial server greeting */ 607 static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, 608 int pop3code, 609 pop3state instate) 610 { 611 CURLcode result = CURLE_OK; 612 struct Curl_easy *data = conn->data; 613 struct pop3_conn *pop3c = &conn->proto.pop3c; 614 const char *line = data->state.buffer; 615 size_t len = strlen(line); 616 size_t i; 617 618 (void)instate; /* no use for this yet */ 619 620 if(pop3code != '+') { 621 failf(data, "Got unexpected pop3-server response"); 622 result = CURLE_WEIRD_SERVER_REPLY; 623 } 624 else { 625 /* Does the server support APOP authentication? */ 626 if(len >= 4 && line[len - 2] == '>') { 627 /* Look for the APOP timestamp */ 628 for(i = 3; i < len - 2; ++i) { 629 if(line[i] == '<') { 630 /* Calculate the length of the timestamp */ 631 size_t timestamplen = len - 1 - i; 632 if(!timestamplen) 633 break; 634 635 /* Allocate some memory for the timestamp */ 636 pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1); 637 638 if(!pop3c->apoptimestamp) 639 break; 640 641 /* Copy the timestamp */ 642 memcpy(pop3c->apoptimestamp, line + i, timestamplen); 643 pop3c->apoptimestamp[timestamplen] = '\0'; 644 645 /* Store the APOP capability */ 646 pop3c->authtypes |= POP3_TYPE_APOP; 647 break; 648 } 649 } 650 } 651 652 result = pop3_perform_capa(conn); 653 } 654 655 return result; 656 } 657 658 /* For CAPA responses */ 659 static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, 660 pop3state instate) 661 { 662 CURLcode result = CURLE_OK; 663 struct Curl_easy *data = conn->data; 664 struct pop3_conn *pop3c = &conn->proto.pop3c; 665 const char *line = data->state.buffer; 666 size_t len = strlen(line); 667 size_t wordlen; 668 669 (void)instate; /* no use for this yet */ 670 671 /* Do we have a untagged continuation response? */ 672 if(pop3code == '*') { 673 /* Does the server support the STLS capability? */ 674 if(len >= 4 && !memcmp(line, "STLS", 4)) 675 pop3c->tls_supported = TRUE; 676 677 /* Does the server support clear text authentication? */ 678 else if(len >= 4 && !memcmp(line, "USER", 4)) 679 pop3c->authtypes |= POP3_TYPE_CLEARTEXT; 680 681 /* Does the server support SASL based authentication? */ 682 else if(len >= 5 && !memcmp(line, "SASL ", 5)) { 683 pop3c->authtypes |= POP3_TYPE_SASL; 684 685 /* Advance past the SASL keyword */ 686 line += 5; 687 len -= 5; 688 689 /* Loop through the data line */ 690 for(;;) { 691 size_t llen; 692 unsigned int mechbit; 693 694 while(len && 695 (*line == ' ' || *line == '\t' || 696 *line == '\r' || *line == '\n')) { 697 698 line++; 699 len--; 700 } 701 702 if(!len) 703 break; 704 705 /* Extract the word */ 706 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && 707 line[wordlen] != '\t' && line[wordlen] != '\r' && 708 line[wordlen] != '\n';) 709 wordlen++; 710 711 /* Test the word for a matching authentication mechanism */ 712 mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); 713 if(mechbit && llen == wordlen) 714 pop3c->sasl.authmechs |= mechbit; 715 716 line += wordlen; 717 len -= wordlen; 718 } 719 } 720 } 721 else if(pop3code == '+') { 722 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { 723 /* We don't have a SSL/TLS connection yet, but SSL is requested */ 724 if(pop3c->tls_supported) 725 /* Switch to TLS connection now */ 726 result = pop3_perform_starttls(conn); 727 else if(data->set.use_ssl == CURLUSESSL_TRY) 728 /* Fallback and carry on with authentication */ 729 result = pop3_perform_authentication(conn); 730 else { 731 failf(data, "STLS not supported."); 732 result = CURLE_USE_SSL_FAILED; 733 } 734 } 735 else 736 result = pop3_perform_authentication(conn); 737 } 738 else { 739 /* Clear text is supported when CAPA isn't recognised */ 740 pop3c->authtypes |= POP3_TYPE_CLEARTEXT; 741 742 result = pop3_perform_authentication(conn); 743 } 744 745 return result; 746 } 747 748 /* For STARTTLS responses */ 749 static CURLcode pop3_state_starttls_resp(struct connectdata *conn, 750 int pop3code, 751 pop3state instate) 752 { 753 CURLcode result = CURLE_OK; 754 struct Curl_easy *data = conn->data; 755 756 (void)instate; /* no use for this yet */ 757 758 if(pop3code != '+') { 759 if(data->set.use_ssl != CURLUSESSL_TRY) { 760 failf(data, "STARTTLS denied"); 761 result = CURLE_USE_SSL_FAILED; 762 } 763 else 764 result = pop3_perform_authentication(conn); 765 } 766 else 767 result = pop3_perform_upgrade_tls(conn); 768 769 return result; 770 } 771 772 /* For SASL authentication responses */ 773 static CURLcode pop3_state_auth_resp(struct connectdata *conn, 774 int pop3code, 775 pop3state instate) 776 { 777 CURLcode result = CURLE_OK; 778 struct Curl_easy *data = conn->data; 779 struct pop3_conn *pop3c = &conn->proto.pop3c; 780 saslprogress progress; 781 782 (void)instate; /* no use for this yet */ 783 784 result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress); 785 if(!result) 786 switch(progress) { 787 case SASL_DONE: 788 state(conn, POP3_STOP); /* Authenticated */ 789 break; 790 case SASL_IDLE: /* No mechanism left after cancellation */ 791 #ifndef CURL_DISABLE_CRYPTO_AUTH 792 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) 793 /* Perform APOP authentication */ 794 result = pop3_perform_apop(conn); 795 else 796 #endif 797 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) 798 /* Perform clear text authentication */ 799 result = pop3_perform_user(conn); 800 else { 801 failf(data, "Authentication cancelled"); 802 result = CURLE_LOGIN_DENIED; 803 } 804 break; 805 default: 806 break; 807 } 808 809 return result; 810 } 811 812 #ifndef CURL_DISABLE_CRYPTO_AUTH 813 /* For APOP responses */ 814 static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code, 815 pop3state instate) 816 { 817 CURLcode result = CURLE_OK; 818 struct Curl_easy *data = conn->data; 819 820 (void)instate; /* no use for this yet */ 821 822 if(pop3code != '+') { 823 failf(data, "Authentication failed: %d", pop3code); 824 result = CURLE_LOGIN_DENIED; 825 } 826 else 827 /* End of connect phase */ 828 state(conn, POP3_STOP); 829 830 return result; 831 } 832 #endif 833 834 /* For USER responses */ 835 static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, 836 pop3state instate) 837 { 838 CURLcode result = CURLE_OK; 839 struct Curl_easy *data = conn->data; 840 841 (void)instate; /* no use for this yet */ 842 843 if(pop3code != '+') { 844 failf(data, "Access denied. %c", pop3code); 845 result = CURLE_LOGIN_DENIED; 846 } 847 else 848 /* Send the PASS command */ 849 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s", 850 conn->passwd ? conn->passwd : ""); 851 if(!result) 852 state(conn, POP3_PASS); 853 854 return result; 855 } 856 857 /* For PASS responses */ 858 static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code, 859 pop3state instate) 860 { 861 CURLcode result = CURLE_OK; 862 struct Curl_easy *data = conn->data; 863 864 (void)instate; /* no use for this yet */ 865 866 if(pop3code != '+') { 867 failf(data, "Access denied. %c", pop3code); 868 result = CURLE_LOGIN_DENIED; 869 } 870 else 871 /* End of connect phase */ 872 state(conn, POP3_STOP); 873 874 return result; 875 } 876 877 /* For command responses */ 878 static CURLcode pop3_state_command_resp(struct connectdata *conn, 879 int pop3code, 880 pop3state instate) 881 { 882 CURLcode result = CURLE_OK; 883 struct Curl_easy *data = conn->data; 884 struct POP3 *pop3 = data->req.protop; 885 struct pop3_conn *pop3c = &conn->proto.pop3c; 886 struct pingpong *pp = &pop3c->pp; 887 888 (void)instate; /* no use for this yet */ 889 890 if(pop3code != '+') { 891 state(conn, POP3_STOP); 892 return CURLE_RECV_ERROR; 893 } 894 895 /* This 'OK' line ends with a CR LF pair which is the two first bytes of the 896 EOB string so count this is two matching bytes. This is necessary to make 897 the code detect the EOB if the only data than comes now is %2e CR LF like 898 when there is no body to return. */ 899 pop3c->eob = 2; 900 901 /* But since this initial CR LF pair is not part of the actual body, we set 902 the strip counter here so that these bytes won't be delivered. */ 903 pop3c->strip = 2; 904 905 if(pop3->transfer == FTPTRANSFER_BODY) { 906 /* POP3 download */ 907 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL); 908 909 if(pp->cache) { 910 /* The header "cache" contains a bunch of data that is actually body 911 content so send it as such. Note that there may even be additional 912 "headers" after the body */ 913 914 if(!data->set.opt_no_body) { 915 result = Curl_pop3_write(conn, pp->cache, pp->cache_size); 916 if(result) 917 return result; 918 } 919 920 /* Free the cache */ 921 Curl_safefree(pp->cache); 922 923 /* Reset the cache size */ 924 pp->cache_size = 0; 925 } 926 } 927 928 /* End of DO phase */ 929 state(conn, POP3_STOP); 930 931 return result; 932 } 933 934 static CURLcode pop3_statemach_act(struct connectdata *conn) 935 { 936 CURLcode result = CURLE_OK; 937 curl_socket_t sock = conn->sock[FIRSTSOCKET]; 938 int pop3code; 939 struct pop3_conn *pop3c = &conn->proto.pop3c; 940 struct pingpong *pp = &pop3c->pp; 941 size_t nread = 0; 942 943 /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */ 944 if(pop3c->state == POP3_UPGRADETLS) 945 return pop3_perform_upgrade_tls(conn); 946 947 /* Flush any data that needs to be sent */ 948 if(pp->sendleft) 949 return Curl_pp_flushsend(pp); 950 951 do { 952 /* Read the response from the server */ 953 result = Curl_pp_readresp(sock, pp, &pop3code, &nread); 954 if(result) 955 return result; 956 957 if(!pop3code) 958 break; 959 960 /* We have now received a full POP3 server response */ 961 switch(pop3c->state) { 962 case POP3_SERVERGREET: 963 result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state); 964 break; 965 966 case POP3_CAPA: 967 result = pop3_state_capa_resp(conn, pop3code, pop3c->state); 968 break; 969 970 case POP3_STARTTLS: 971 result = pop3_state_starttls_resp(conn, pop3code, pop3c->state); 972 break; 973 974 case POP3_AUTH: 975 result = pop3_state_auth_resp(conn, pop3code, pop3c->state); 976 break; 977 978 #ifndef CURL_DISABLE_CRYPTO_AUTH 979 case POP3_APOP: 980 result = pop3_state_apop_resp(conn, pop3code, pop3c->state); 981 break; 982 #endif 983 984 case POP3_USER: 985 result = pop3_state_user_resp(conn, pop3code, pop3c->state); 986 break; 987 988 case POP3_PASS: 989 result = pop3_state_pass_resp(conn, pop3code, pop3c->state); 990 break; 991 992 case POP3_COMMAND: 993 result = pop3_state_command_resp(conn, pop3code, pop3c->state); 994 break; 995 996 case POP3_QUIT: 997 /* fallthrough, just stop! */ 998 default: 999 /* internal error */ 1000 state(conn, POP3_STOP); 1001 break; 1002 } 1003 } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp)); 1004 1005 return result; 1006 } 1007 1008 /* Called repeatedly until done from multi.c */ 1009 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done) 1010 { 1011 CURLcode result = CURLE_OK; 1012 struct pop3_conn *pop3c = &conn->proto.pop3c; 1013 1014 if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) { 1015 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone); 1016 if(result || !pop3c->ssldone) 1017 return result; 1018 } 1019 1020 result = Curl_pp_statemach(&pop3c->pp, FALSE); 1021 *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE; 1022 1023 return result; 1024 } 1025 1026 static CURLcode pop3_block_statemach(struct connectdata *conn) 1027 { 1028 CURLcode result = CURLE_OK; 1029 struct pop3_conn *pop3c = &conn->proto.pop3c; 1030 1031 while(pop3c->state != POP3_STOP && !result) 1032 result = Curl_pp_statemach(&pop3c->pp, TRUE); 1033 1034 return result; 1035 } 1036 1037 /* Allocate and initialize the POP3 struct for the current Curl_easy if 1038 required */ 1039 static CURLcode pop3_init(struct connectdata *conn) 1040 { 1041 CURLcode result = CURLE_OK; 1042 struct Curl_easy *data = conn->data; 1043 struct POP3 *pop3; 1044 1045 pop3 = data->req.protop = calloc(sizeof(struct POP3), 1); 1046 if(!pop3) 1047 result = CURLE_OUT_OF_MEMORY; 1048 1049 return result; 1050 } 1051 1052 /* For the POP3 "protocol connect" and "doing" phases only */ 1053 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, 1054 int numsocks) 1055 { 1056 return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks); 1057 } 1058 1059 /*********************************************************************** 1060 * 1061 * pop3_connect() 1062 * 1063 * This function should do everything that is to be considered a part of the 1064 * connection phase. 1065 * 1066 * The variable 'done' points to will be TRUE if the protocol-layer connect 1067 * phase is done when this function returns, or FALSE if not. 1068 */ 1069 static CURLcode pop3_connect(struct connectdata *conn, bool *done) 1070 { 1071 CURLcode result = CURLE_OK; 1072 struct pop3_conn *pop3c = &conn->proto.pop3c; 1073 struct pingpong *pp = &pop3c->pp; 1074 1075 *done = FALSE; /* default to not done yet */ 1076 1077 /* We always support persistent connections in POP3 */ 1078 connkeep(conn, "POP3 default"); 1079 1080 /* Set the default response time-out */ 1081 pp->response_time = RESP_TIMEOUT; 1082 pp->statemach_act = pop3_statemach_act; 1083 pp->endofresp = pop3_endofresp; 1084 pp->conn = conn; 1085 1086 /* Set the default preferred authentication type and mechanism */ 1087 pop3c->preftype = POP3_TYPE_ANY; 1088 Curl_sasl_init(&pop3c->sasl, &saslpop3); 1089 1090 /* Initialise the pingpong layer */ 1091 Curl_pp_init(pp); 1092 1093 /* Parse the URL options */ 1094 result = pop3_parse_url_options(conn); 1095 if(result) 1096 return result; 1097 1098 /* Start off waiting for the server greeting response */ 1099 state(conn, POP3_SERVERGREET); 1100 1101 result = pop3_multi_statemach(conn, done); 1102 1103 return result; 1104 } 1105 1106 /*********************************************************************** 1107 * 1108 * pop3_done() 1109 * 1110 * The DONE function. This does what needs to be done after a single DO has 1111 * performed. 1112 * 1113 * Input argument is already checked for validity. 1114 */ 1115 static CURLcode pop3_done(struct connectdata *conn, CURLcode status, 1116 bool premature) 1117 { 1118 CURLcode result = CURLE_OK; 1119 struct Curl_easy *data = conn->data; 1120 struct POP3 *pop3 = data->req.protop; 1121 1122 (void)premature; 1123 1124 if(!pop3) 1125 return CURLE_OK; 1126 1127 if(status) { 1128 connclose(conn, "POP3 done with bad status"); 1129 result = status; /* use the already set error code */ 1130 } 1131 1132 /* Cleanup our per-request based variables */ 1133 Curl_safefree(pop3->id); 1134 Curl_safefree(pop3->custom); 1135 1136 /* Clear the transfer mode for the next request */ 1137 pop3->transfer = FTPTRANSFER_BODY; 1138 1139 return result; 1140 } 1141 1142 /*********************************************************************** 1143 * 1144 * pop3_perform() 1145 * 1146 * This is the actual DO function for POP3. Get a message/listing according to 1147 * the options previously setup. 1148 */ 1149 static CURLcode pop3_perform(struct connectdata *conn, bool *connected, 1150 bool *dophase_done) 1151 { 1152 /* This is POP3 and no proxy */ 1153 CURLcode result = CURLE_OK; 1154 struct POP3 *pop3 = conn->data->req.protop; 1155 1156 DEBUGF(infof(conn->data, "DO phase starts\n")); 1157 1158 if(conn->data->set.opt_no_body) { 1159 /* Requested no body means no transfer */ 1160 pop3->transfer = FTPTRANSFER_INFO; 1161 } 1162 1163 *dophase_done = FALSE; /* not done yet */ 1164 1165 /* Start the first command in the DO phase */ 1166 result = pop3_perform_command(conn); 1167 if(result) 1168 return result; 1169 1170 /* Run the state-machine */ 1171 result = pop3_multi_statemach(conn, dophase_done); 1172 1173 *connected = conn->bits.tcpconnect[FIRSTSOCKET]; 1174 1175 if(*dophase_done) 1176 DEBUGF(infof(conn->data, "DO phase is complete\n")); 1177 1178 return result; 1179 } 1180 1181 /*********************************************************************** 1182 * 1183 * pop3_do() 1184 * 1185 * This function is registered as 'curl_do' function. It decodes the path 1186 * parts etc as a wrapper to the actual DO function (pop3_perform). 1187 * 1188 * The input argument is already checked for validity. 1189 */ 1190 static CURLcode pop3_do(struct connectdata *conn, bool *done) 1191 { 1192 CURLcode result = CURLE_OK; 1193 1194 *done = FALSE; /* default to false */ 1195 1196 /* Parse the URL path */ 1197 result = pop3_parse_url_path(conn); 1198 if(result) 1199 return result; 1200 1201 /* Parse the custom request */ 1202 result = pop3_parse_custom_request(conn); 1203 if(result) 1204 return result; 1205 1206 result = pop3_regular_transfer(conn, done); 1207 1208 return result; 1209 } 1210 1211 /*********************************************************************** 1212 * 1213 * pop3_disconnect() 1214 * 1215 * Disconnect from an POP3 server. Cleanup protocol-specific per-connection 1216 * resources. BLOCKING. 1217 */ 1218 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection) 1219 { 1220 struct pop3_conn *pop3c = &conn->proto.pop3c; 1221 1222 /* We cannot send quit unconditionally. If this connection is stale or 1223 bad in any way, sending quit and waiting around here will make the 1224 disconnect wait in vain and cause more problems than we need to. */ 1225 1226 /* The POP3 session may or may not have been allocated/setup at this 1227 point! */ 1228 if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart) 1229 if(!pop3_perform_quit(conn)) 1230 (void)pop3_block_statemach(conn); /* ignore errors on QUIT */ 1231 1232 /* Disconnect from the server */ 1233 Curl_pp_disconnect(&pop3c->pp); 1234 1235 /* Cleanup the SASL module */ 1236 Curl_sasl_cleanup(conn, pop3c->sasl.authused); 1237 1238 /* Cleanup our connection based variables */ 1239 Curl_safefree(pop3c->apoptimestamp); 1240 1241 return CURLE_OK; 1242 } 1243 1244 /* Call this when the DO phase has completed */ 1245 static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) 1246 { 1247 (void)conn; 1248 (void)connected; 1249 1250 return CURLE_OK; 1251 } 1252 1253 /* Called from multi.c while DOing */ 1254 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done) 1255 { 1256 CURLcode result = pop3_multi_statemach(conn, dophase_done); 1257 1258 if(result) 1259 DEBUGF(infof(conn->data, "DO phase failed\n")); 1260 else if(*dophase_done) { 1261 result = pop3_dophase_done(conn, FALSE /* not connected */); 1262 1263 DEBUGF(infof(conn->data, "DO phase is complete\n")); 1264 } 1265 1266 return result; 1267 } 1268 1269 /*********************************************************************** 1270 * 1271 * pop3_regular_transfer() 1272 * 1273 * The input argument is already checked for validity. 1274 * 1275 * Performs all commands done before a regular transfer between a local and a 1276 * remote host. 1277 */ 1278 static CURLcode pop3_regular_transfer(struct connectdata *conn, 1279 bool *dophase_done) 1280 { 1281 CURLcode result = CURLE_OK; 1282 bool connected = FALSE; 1283 struct Curl_easy *data = conn->data; 1284 1285 /* Make sure size is unknown at this point */ 1286 data->req.size = -1; 1287 1288 /* Set the progress data */ 1289 Curl_pgrsSetUploadCounter(data, 0); 1290 Curl_pgrsSetDownloadCounter(data, 0); 1291 Curl_pgrsSetUploadSize(data, -1); 1292 Curl_pgrsSetDownloadSize(data, -1); 1293 1294 /* Carry out the perform */ 1295 result = pop3_perform(conn, &connected, dophase_done); 1296 1297 /* Perform post DO phase operations if necessary */ 1298 if(!result && *dophase_done) 1299 result = pop3_dophase_done(conn, connected); 1300 1301 return result; 1302 } 1303 1304 static CURLcode pop3_setup_connection(struct connectdata *conn) 1305 { 1306 struct Curl_easy *data = conn->data; 1307 1308 /* Initialise the POP3 layer */ 1309 CURLcode result = pop3_init(conn); 1310 if(result) 1311 return result; 1312 1313 /* Clear the TLS upgraded flag */ 1314 conn->tls_upgraded = FALSE; 1315 data->state.path++; /* don't include the initial slash */ 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.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 */ 1545