113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci * RFC1734 POP3 Authentication 2413498266Sopenharmony_ci * RFC1939 POP3 protocol 2513498266Sopenharmony_ci * RFC2195 CRAM-MD5 authentication 2613498266Sopenharmony_ci * RFC2384 POP URL Scheme 2713498266Sopenharmony_ci * RFC2449 POP3 Extension Mechanism 2813498266Sopenharmony_ci * RFC2595 Using TLS with IMAP, POP3 and ACAP 2913498266Sopenharmony_ci * RFC2831 DIGEST-MD5 authentication 3013498266Sopenharmony_ci * RFC4422 Simple Authentication and Security Layer (SASL) 3113498266Sopenharmony_ci * RFC4616 PLAIN authentication 3213498266Sopenharmony_ci * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism 3313498266Sopenharmony_ci * RFC5034 POP3 SASL Authentication Mechanism 3413498266Sopenharmony_ci * RFC6749 OAuth 2.0 Authorization Framework 3513498266Sopenharmony_ci * RFC8314 Use of TLS for Email Submission and Access 3613498266Sopenharmony_ci * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt> 3713498266Sopenharmony_ci * 3813498266Sopenharmony_ci ***************************************************************************/ 3913498266Sopenharmony_ci 4013498266Sopenharmony_ci#include "curl_setup.h" 4113498266Sopenharmony_ci 4213498266Sopenharmony_ci#ifndef CURL_DISABLE_POP3 4313498266Sopenharmony_ci 4413498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 4513498266Sopenharmony_ci#include <netinet/in.h> 4613498266Sopenharmony_ci#endif 4713498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H 4813498266Sopenharmony_ci#include <arpa/inet.h> 4913498266Sopenharmony_ci#endif 5013498266Sopenharmony_ci#ifdef HAVE_NETDB_H 5113498266Sopenharmony_ci#include <netdb.h> 5213498266Sopenharmony_ci#endif 5313498266Sopenharmony_ci#ifdef __VMS 5413498266Sopenharmony_ci#include <in.h> 5513498266Sopenharmony_ci#include <inet.h> 5613498266Sopenharmony_ci#endif 5713498266Sopenharmony_ci 5813498266Sopenharmony_ci#include <curl/curl.h> 5913498266Sopenharmony_ci#include "urldata.h" 6013498266Sopenharmony_ci#include "sendf.h" 6113498266Sopenharmony_ci#include "hostip.h" 6213498266Sopenharmony_ci#include "progress.h" 6313498266Sopenharmony_ci#include "transfer.h" 6413498266Sopenharmony_ci#include "escape.h" 6513498266Sopenharmony_ci#include "http.h" /* for HTTP proxy tunnel stuff */ 6613498266Sopenharmony_ci#include "socks.h" 6713498266Sopenharmony_ci#include "pop3.h" 6813498266Sopenharmony_ci#include "strtoofft.h" 6913498266Sopenharmony_ci#include "strcase.h" 7013498266Sopenharmony_ci#include "vtls/vtls.h" 7113498266Sopenharmony_ci#include "cfilters.h" 7213498266Sopenharmony_ci#include "connect.h" 7313498266Sopenharmony_ci#include "select.h" 7413498266Sopenharmony_ci#include "multiif.h" 7513498266Sopenharmony_ci#include "url.h" 7613498266Sopenharmony_ci#include "bufref.h" 7713498266Sopenharmony_ci#include "curl_sasl.h" 7813498266Sopenharmony_ci#include "curl_md5.h" 7913498266Sopenharmony_ci#include "warnless.h" 8013498266Sopenharmony_ci#include "strdup.h" 8113498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 8213498266Sopenharmony_ci#include "curl_printf.h" 8313498266Sopenharmony_ci#include "curl_memory.h" 8413498266Sopenharmony_ci#include "memdebug.h" 8513498266Sopenharmony_ci 8613498266Sopenharmony_ci/* Local API functions */ 8713498266Sopenharmony_cistatic CURLcode pop3_regular_transfer(struct Curl_easy *data, bool *done); 8813498266Sopenharmony_cistatic CURLcode pop3_do(struct Curl_easy *data, bool *done); 8913498266Sopenharmony_cistatic CURLcode pop3_done(struct Curl_easy *data, CURLcode status, 9013498266Sopenharmony_ci bool premature); 9113498266Sopenharmony_cistatic CURLcode pop3_connect(struct Curl_easy *data, bool *done); 9213498266Sopenharmony_cistatic CURLcode pop3_disconnect(struct Curl_easy *data, 9313498266Sopenharmony_ci struct connectdata *conn, bool dead); 9413498266Sopenharmony_cistatic CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done); 9513498266Sopenharmony_cistatic int pop3_getsock(struct Curl_easy *data, 9613498266Sopenharmony_ci struct connectdata *conn, curl_socket_t *socks); 9713498266Sopenharmony_cistatic CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done); 9813498266Sopenharmony_cistatic CURLcode pop3_setup_connection(struct Curl_easy *data, 9913498266Sopenharmony_ci struct connectdata *conn); 10013498266Sopenharmony_cistatic CURLcode pop3_parse_url_options(struct connectdata *conn); 10113498266Sopenharmony_cistatic CURLcode pop3_parse_url_path(struct Curl_easy *data); 10213498266Sopenharmony_cistatic CURLcode pop3_parse_custom_request(struct Curl_easy *data); 10313498266Sopenharmony_cistatic CURLcode pop3_perform_auth(struct Curl_easy *data, const char *mech, 10413498266Sopenharmony_ci const struct bufref *initresp); 10513498266Sopenharmony_cistatic CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech, 10613498266Sopenharmony_ci const struct bufref *resp); 10713498266Sopenharmony_cistatic CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech); 10813498266Sopenharmony_cistatic CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out); 10913498266Sopenharmony_ci 11013498266Sopenharmony_ci/* 11113498266Sopenharmony_ci * POP3 protocol handler. 11213498266Sopenharmony_ci */ 11313498266Sopenharmony_ci 11413498266Sopenharmony_ciconst struct Curl_handler Curl_handler_pop3 = { 11513498266Sopenharmony_ci "POP3", /* scheme */ 11613498266Sopenharmony_ci pop3_setup_connection, /* setup_connection */ 11713498266Sopenharmony_ci pop3_do, /* do_it */ 11813498266Sopenharmony_ci pop3_done, /* done */ 11913498266Sopenharmony_ci ZERO_NULL, /* do_more */ 12013498266Sopenharmony_ci pop3_connect, /* connect_it */ 12113498266Sopenharmony_ci pop3_multi_statemach, /* connecting */ 12213498266Sopenharmony_ci pop3_doing, /* doing */ 12313498266Sopenharmony_ci pop3_getsock, /* proto_getsock */ 12413498266Sopenharmony_ci pop3_getsock, /* doing_getsock */ 12513498266Sopenharmony_ci ZERO_NULL, /* domore_getsock */ 12613498266Sopenharmony_ci ZERO_NULL, /* perform_getsock */ 12713498266Sopenharmony_ci pop3_disconnect, /* disconnect */ 12813498266Sopenharmony_ci ZERO_NULL, /* write_resp */ 12913498266Sopenharmony_ci ZERO_NULL, /* connection_check */ 13013498266Sopenharmony_ci ZERO_NULL, /* attach connection */ 13113498266Sopenharmony_ci PORT_POP3, /* defport */ 13213498266Sopenharmony_ci CURLPROTO_POP3, /* protocol */ 13313498266Sopenharmony_ci CURLPROTO_POP3, /* family */ 13413498266Sopenharmony_ci PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ 13513498266Sopenharmony_ci PROTOPT_URLOPTIONS 13613498266Sopenharmony_ci}; 13713498266Sopenharmony_ci 13813498266Sopenharmony_ci#ifdef USE_SSL 13913498266Sopenharmony_ci/* 14013498266Sopenharmony_ci * POP3S protocol handler. 14113498266Sopenharmony_ci */ 14213498266Sopenharmony_ci 14313498266Sopenharmony_ciconst struct Curl_handler Curl_handler_pop3s = { 14413498266Sopenharmony_ci "POP3S", /* scheme */ 14513498266Sopenharmony_ci pop3_setup_connection, /* setup_connection */ 14613498266Sopenharmony_ci pop3_do, /* do_it */ 14713498266Sopenharmony_ci pop3_done, /* done */ 14813498266Sopenharmony_ci ZERO_NULL, /* do_more */ 14913498266Sopenharmony_ci pop3_connect, /* connect_it */ 15013498266Sopenharmony_ci pop3_multi_statemach, /* connecting */ 15113498266Sopenharmony_ci pop3_doing, /* doing */ 15213498266Sopenharmony_ci pop3_getsock, /* proto_getsock */ 15313498266Sopenharmony_ci pop3_getsock, /* doing_getsock */ 15413498266Sopenharmony_ci ZERO_NULL, /* domore_getsock */ 15513498266Sopenharmony_ci ZERO_NULL, /* perform_getsock */ 15613498266Sopenharmony_ci pop3_disconnect, /* disconnect */ 15713498266Sopenharmony_ci ZERO_NULL, /* write_resp */ 15813498266Sopenharmony_ci ZERO_NULL, /* connection_check */ 15913498266Sopenharmony_ci ZERO_NULL, /* attach connection */ 16013498266Sopenharmony_ci PORT_POP3S, /* defport */ 16113498266Sopenharmony_ci CURLPROTO_POP3S, /* protocol */ 16213498266Sopenharmony_ci CURLPROTO_POP3, /* family */ 16313498266Sopenharmony_ci PROTOPT_CLOSEACTION | PROTOPT_SSL 16413498266Sopenharmony_ci | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ 16513498266Sopenharmony_ci}; 16613498266Sopenharmony_ci#endif 16713498266Sopenharmony_ci 16813498266Sopenharmony_ci/* SASL parameters for the pop3 protocol */ 16913498266Sopenharmony_cistatic const struct SASLproto saslpop3 = { 17013498266Sopenharmony_ci "pop", /* The service name */ 17113498266Sopenharmony_ci pop3_perform_auth, /* Send authentication command */ 17213498266Sopenharmony_ci pop3_continue_auth, /* Send authentication continuation */ 17313498266Sopenharmony_ci pop3_cancel_auth, /* Send authentication cancellation */ 17413498266Sopenharmony_ci pop3_get_message, /* Get SASL response message */ 17513498266Sopenharmony_ci 255 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */ 17613498266Sopenharmony_ci '*', /* Code received when continuation is expected */ 17713498266Sopenharmony_ci '+', /* Code to receive upon authentication success */ 17813498266Sopenharmony_ci SASL_AUTH_DEFAULT, /* Default mechanisms */ 17913498266Sopenharmony_ci SASL_FLAG_BASE64 /* Configuration flags */ 18013498266Sopenharmony_ci}; 18113498266Sopenharmony_ci 18213498266Sopenharmony_ci#ifdef USE_SSL 18313498266Sopenharmony_cistatic void pop3_to_pop3s(struct connectdata *conn) 18413498266Sopenharmony_ci{ 18513498266Sopenharmony_ci /* Change the connection handler */ 18613498266Sopenharmony_ci conn->handler = &Curl_handler_pop3s; 18713498266Sopenharmony_ci 18813498266Sopenharmony_ci /* Set the connection's upgraded to TLS flag */ 18913498266Sopenharmony_ci conn->bits.tls_upgraded = TRUE; 19013498266Sopenharmony_ci} 19113498266Sopenharmony_ci#else 19213498266Sopenharmony_ci#define pop3_to_pop3s(x) Curl_nop_stmt 19313498266Sopenharmony_ci#endif 19413498266Sopenharmony_ci 19513498266Sopenharmony_ci/*********************************************************************** 19613498266Sopenharmony_ci * 19713498266Sopenharmony_ci * pop3_endofresp() 19813498266Sopenharmony_ci * 19913498266Sopenharmony_ci * Checks for an ending POP3 status code at the start of the given string, but 20013498266Sopenharmony_ci * also detects the APOP timestamp from the server greeting and various 20113498266Sopenharmony_ci * capabilities from the CAPA response including the supported authentication 20213498266Sopenharmony_ci * types and allowed SASL mechanisms. 20313498266Sopenharmony_ci */ 20413498266Sopenharmony_cistatic bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn, 20513498266Sopenharmony_ci char *line, size_t len, int *resp) 20613498266Sopenharmony_ci{ 20713498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 20813498266Sopenharmony_ci (void)data; 20913498266Sopenharmony_ci 21013498266Sopenharmony_ci /* Do we have an error response? */ 21113498266Sopenharmony_ci if(len >= 4 && !memcmp("-ERR", line, 4)) { 21213498266Sopenharmony_ci *resp = '-'; 21313498266Sopenharmony_ci 21413498266Sopenharmony_ci return TRUE; 21513498266Sopenharmony_ci } 21613498266Sopenharmony_ci 21713498266Sopenharmony_ci /* Are we processing CAPA command responses? */ 21813498266Sopenharmony_ci if(pop3c->state == POP3_CAPA) { 21913498266Sopenharmony_ci /* Do we have the terminating line? */ 22013498266Sopenharmony_ci if(len >= 1 && line[0] == '.') 22113498266Sopenharmony_ci /* Treat the response as a success */ 22213498266Sopenharmony_ci *resp = '+'; 22313498266Sopenharmony_ci else 22413498266Sopenharmony_ci /* Treat the response as an untagged continuation */ 22513498266Sopenharmony_ci *resp = '*'; 22613498266Sopenharmony_ci 22713498266Sopenharmony_ci return TRUE; 22813498266Sopenharmony_ci } 22913498266Sopenharmony_ci 23013498266Sopenharmony_ci /* Do we have a success response? */ 23113498266Sopenharmony_ci if(len >= 3 && !memcmp("+OK", line, 3)) { 23213498266Sopenharmony_ci *resp = '+'; 23313498266Sopenharmony_ci 23413498266Sopenharmony_ci return TRUE; 23513498266Sopenharmony_ci } 23613498266Sopenharmony_ci 23713498266Sopenharmony_ci /* Do we have a continuation response? */ 23813498266Sopenharmony_ci if(len >= 1 && line[0] == '+') { 23913498266Sopenharmony_ci *resp = '*'; 24013498266Sopenharmony_ci 24113498266Sopenharmony_ci return TRUE; 24213498266Sopenharmony_ci } 24313498266Sopenharmony_ci 24413498266Sopenharmony_ci return FALSE; /* Nothing for us */ 24513498266Sopenharmony_ci} 24613498266Sopenharmony_ci 24713498266Sopenharmony_ci/*********************************************************************** 24813498266Sopenharmony_ci * 24913498266Sopenharmony_ci * pop3_get_message() 25013498266Sopenharmony_ci * 25113498266Sopenharmony_ci * Gets the authentication message from the response buffer. 25213498266Sopenharmony_ci */ 25313498266Sopenharmony_cistatic CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out) 25413498266Sopenharmony_ci{ 25513498266Sopenharmony_ci char *message = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf); 25613498266Sopenharmony_ci size_t len = data->conn->proto.pop3c.pp.nfinal; 25713498266Sopenharmony_ci 25813498266Sopenharmony_ci if(len > 2) { 25913498266Sopenharmony_ci /* Find the start of the message */ 26013498266Sopenharmony_ci len -= 2; 26113498266Sopenharmony_ci for(message += 2; *message == ' ' || *message == '\t'; message++, len--) 26213498266Sopenharmony_ci ; 26313498266Sopenharmony_ci 26413498266Sopenharmony_ci /* Find the end of the message */ 26513498266Sopenharmony_ci while(len--) 26613498266Sopenharmony_ci if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && 26713498266Sopenharmony_ci message[len] != '\t') 26813498266Sopenharmony_ci break; 26913498266Sopenharmony_ci 27013498266Sopenharmony_ci /* Terminate the message */ 27113498266Sopenharmony_ci message[++len] = '\0'; 27213498266Sopenharmony_ci Curl_bufref_set(out, message, len, NULL); 27313498266Sopenharmony_ci } 27413498266Sopenharmony_ci else 27513498266Sopenharmony_ci /* junk input => zero length output */ 27613498266Sopenharmony_ci Curl_bufref_set(out, "", 0, NULL); 27713498266Sopenharmony_ci 27813498266Sopenharmony_ci return CURLE_OK; 27913498266Sopenharmony_ci} 28013498266Sopenharmony_ci 28113498266Sopenharmony_ci/*********************************************************************** 28213498266Sopenharmony_ci * 28313498266Sopenharmony_ci * pop3_state() 28413498266Sopenharmony_ci * 28513498266Sopenharmony_ci * This is the ONLY way to change POP3 state! 28613498266Sopenharmony_ci */ 28713498266Sopenharmony_cistatic void pop3_state(struct Curl_easy *data, pop3state newstate) 28813498266Sopenharmony_ci{ 28913498266Sopenharmony_ci struct pop3_conn *pop3c = &data->conn->proto.pop3c; 29013498266Sopenharmony_ci#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 29113498266Sopenharmony_ci /* for debug purposes */ 29213498266Sopenharmony_ci static const char * const names[] = { 29313498266Sopenharmony_ci "STOP", 29413498266Sopenharmony_ci "SERVERGREET", 29513498266Sopenharmony_ci "CAPA", 29613498266Sopenharmony_ci "STARTTLS", 29713498266Sopenharmony_ci "UPGRADETLS", 29813498266Sopenharmony_ci "AUTH", 29913498266Sopenharmony_ci "APOP", 30013498266Sopenharmony_ci "USER", 30113498266Sopenharmony_ci "PASS", 30213498266Sopenharmony_ci "COMMAND", 30313498266Sopenharmony_ci "QUIT", 30413498266Sopenharmony_ci /* LAST */ 30513498266Sopenharmony_ci }; 30613498266Sopenharmony_ci 30713498266Sopenharmony_ci if(pop3c->state != newstate) 30813498266Sopenharmony_ci infof(data, "POP3 %p state change from %s to %s", 30913498266Sopenharmony_ci (void *)pop3c, names[pop3c->state], names[newstate]); 31013498266Sopenharmony_ci#endif 31113498266Sopenharmony_ci 31213498266Sopenharmony_ci pop3c->state = newstate; 31313498266Sopenharmony_ci} 31413498266Sopenharmony_ci 31513498266Sopenharmony_ci/*********************************************************************** 31613498266Sopenharmony_ci * 31713498266Sopenharmony_ci * pop3_perform_capa() 31813498266Sopenharmony_ci * 31913498266Sopenharmony_ci * Sends the CAPA command in order to obtain a list of server side supported 32013498266Sopenharmony_ci * capabilities. 32113498266Sopenharmony_ci */ 32213498266Sopenharmony_cistatic CURLcode pop3_perform_capa(struct Curl_easy *data, 32313498266Sopenharmony_ci struct connectdata *conn) 32413498266Sopenharmony_ci{ 32513498266Sopenharmony_ci CURLcode result = CURLE_OK; 32613498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 32713498266Sopenharmony_ci 32813498266Sopenharmony_ci pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */ 32913498266Sopenharmony_ci pop3c->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */ 33013498266Sopenharmony_ci pop3c->tls_supported = FALSE; /* Clear the TLS capability */ 33113498266Sopenharmony_ci 33213498266Sopenharmony_ci /* Send the CAPA command */ 33313498266Sopenharmony_ci result = Curl_pp_sendf(data, &pop3c->pp, "%s", "CAPA"); 33413498266Sopenharmony_ci 33513498266Sopenharmony_ci if(!result) 33613498266Sopenharmony_ci pop3_state(data, POP3_CAPA); 33713498266Sopenharmony_ci 33813498266Sopenharmony_ci return result; 33913498266Sopenharmony_ci} 34013498266Sopenharmony_ci 34113498266Sopenharmony_ci/*********************************************************************** 34213498266Sopenharmony_ci * 34313498266Sopenharmony_ci * pop3_perform_starttls() 34413498266Sopenharmony_ci * 34513498266Sopenharmony_ci * Sends the STLS command to start the upgrade to TLS. 34613498266Sopenharmony_ci */ 34713498266Sopenharmony_cistatic CURLcode pop3_perform_starttls(struct Curl_easy *data, 34813498266Sopenharmony_ci struct connectdata *conn) 34913498266Sopenharmony_ci{ 35013498266Sopenharmony_ci /* Send the STLS command */ 35113498266Sopenharmony_ci CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "STLS"); 35213498266Sopenharmony_ci 35313498266Sopenharmony_ci if(!result) 35413498266Sopenharmony_ci pop3_state(data, POP3_STARTTLS); 35513498266Sopenharmony_ci 35613498266Sopenharmony_ci return result; 35713498266Sopenharmony_ci} 35813498266Sopenharmony_ci 35913498266Sopenharmony_ci/*********************************************************************** 36013498266Sopenharmony_ci * 36113498266Sopenharmony_ci * pop3_perform_upgrade_tls() 36213498266Sopenharmony_ci * 36313498266Sopenharmony_ci * Performs the upgrade to TLS. 36413498266Sopenharmony_ci */ 36513498266Sopenharmony_cistatic CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data, 36613498266Sopenharmony_ci struct connectdata *conn) 36713498266Sopenharmony_ci{ 36813498266Sopenharmony_ci /* Start the SSL connection */ 36913498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 37013498266Sopenharmony_ci CURLcode result; 37113498266Sopenharmony_ci bool ssldone = FALSE; 37213498266Sopenharmony_ci 37313498266Sopenharmony_ci if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) { 37413498266Sopenharmony_ci result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET); 37513498266Sopenharmony_ci if(result) 37613498266Sopenharmony_ci goto out; 37713498266Sopenharmony_ci } 37813498266Sopenharmony_ci 37913498266Sopenharmony_ci result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); 38013498266Sopenharmony_ci 38113498266Sopenharmony_ci if(!result) { 38213498266Sopenharmony_ci pop3c->ssldone = ssldone; 38313498266Sopenharmony_ci if(pop3c->state != POP3_UPGRADETLS) 38413498266Sopenharmony_ci pop3_state(data, POP3_UPGRADETLS); 38513498266Sopenharmony_ci 38613498266Sopenharmony_ci if(pop3c->ssldone) { 38713498266Sopenharmony_ci pop3_to_pop3s(conn); 38813498266Sopenharmony_ci result = pop3_perform_capa(data, conn); 38913498266Sopenharmony_ci } 39013498266Sopenharmony_ci } 39113498266Sopenharmony_ciout: 39213498266Sopenharmony_ci return result; 39313498266Sopenharmony_ci} 39413498266Sopenharmony_ci 39513498266Sopenharmony_ci/*********************************************************************** 39613498266Sopenharmony_ci * 39713498266Sopenharmony_ci * pop3_perform_user() 39813498266Sopenharmony_ci * 39913498266Sopenharmony_ci * Sends a clear text USER command to authenticate with. 40013498266Sopenharmony_ci */ 40113498266Sopenharmony_cistatic CURLcode pop3_perform_user(struct Curl_easy *data, 40213498266Sopenharmony_ci struct connectdata *conn) 40313498266Sopenharmony_ci{ 40413498266Sopenharmony_ci CURLcode result = CURLE_OK; 40513498266Sopenharmony_ci 40613498266Sopenharmony_ci /* Check we have a username and password to authenticate with and end the 40713498266Sopenharmony_ci connect phase if we don't */ 40813498266Sopenharmony_ci if(!data->state.aptr.user) { 40913498266Sopenharmony_ci pop3_state(data, POP3_STOP); 41013498266Sopenharmony_ci 41113498266Sopenharmony_ci return result; 41213498266Sopenharmony_ci } 41313498266Sopenharmony_ci 41413498266Sopenharmony_ci /* Send the USER command */ 41513498266Sopenharmony_ci result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "USER %s", 41613498266Sopenharmony_ci conn->user ? conn->user : ""); 41713498266Sopenharmony_ci if(!result) 41813498266Sopenharmony_ci pop3_state(data, POP3_USER); 41913498266Sopenharmony_ci 42013498266Sopenharmony_ci return result; 42113498266Sopenharmony_ci} 42213498266Sopenharmony_ci 42313498266Sopenharmony_ci#ifndef CURL_DISABLE_DIGEST_AUTH 42413498266Sopenharmony_ci/*********************************************************************** 42513498266Sopenharmony_ci * 42613498266Sopenharmony_ci * pop3_perform_apop() 42713498266Sopenharmony_ci * 42813498266Sopenharmony_ci * Sends an APOP command to authenticate with. 42913498266Sopenharmony_ci */ 43013498266Sopenharmony_cistatic CURLcode pop3_perform_apop(struct Curl_easy *data, 43113498266Sopenharmony_ci struct connectdata *conn) 43213498266Sopenharmony_ci{ 43313498266Sopenharmony_ci CURLcode result = CURLE_OK; 43413498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 43513498266Sopenharmony_ci size_t i; 43613498266Sopenharmony_ci struct MD5_context *ctxt; 43713498266Sopenharmony_ci unsigned char digest[MD5_DIGEST_LEN]; 43813498266Sopenharmony_ci char secret[2 * MD5_DIGEST_LEN + 1]; 43913498266Sopenharmony_ci 44013498266Sopenharmony_ci /* Check we have a username and password to authenticate with and end the 44113498266Sopenharmony_ci connect phase if we don't */ 44213498266Sopenharmony_ci if(!data->state.aptr.user) { 44313498266Sopenharmony_ci pop3_state(data, POP3_STOP); 44413498266Sopenharmony_ci 44513498266Sopenharmony_ci return result; 44613498266Sopenharmony_ci } 44713498266Sopenharmony_ci 44813498266Sopenharmony_ci /* Create the digest */ 44913498266Sopenharmony_ci ctxt = Curl_MD5_init(Curl_DIGEST_MD5); 45013498266Sopenharmony_ci if(!ctxt) 45113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 45213498266Sopenharmony_ci 45313498266Sopenharmony_ci Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp, 45413498266Sopenharmony_ci curlx_uztoui(strlen(pop3c->apoptimestamp))); 45513498266Sopenharmony_ci 45613498266Sopenharmony_ci Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd, 45713498266Sopenharmony_ci curlx_uztoui(strlen(conn->passwd))); 45813498266Sopenharmony_ci 45913498266Sopenharmony_ci /* Finalise the digest */ 46013498266Sopenharmony_ci Curl_MD5_final(ctxt, digest); 46113498266Sopenharmony_ci 46213498266Sopenharmony_ci /* Convert the calculated 16 octet digest into a 32 byte hex string */ 46313498266Sopenharmony_ci for(i = 0; i < MD5_DIGEST_LEN; i++) 46413498266Sopenharmony_ci msnprintf(&secret[2 * i], 3, "%02x", digest[i]); 46513498266Sopenharmony_ci 46613498266Sopenharmony_ci result = Curl_pp_sendf(data, &pop3c->pp, "APOP %s %s", conn->user, secret); 46713498266Sopenharmony_ci 46813498266Sopenharmony_ci if(!result) 46913498266Sopenharmony_ci pop3_state(data, POP3_APOP); 47013498266Sopenharmony_ci 47113498266Sopenharmony_ci return result; 47213498266Sopenharmony_ci} 47313498266Sopenharmony_ci#endif 47413498266Sopenharmony_ci 47513498266Sopenharmony_ci/*********************************************************************** 47613498266Sopenharmony_ci * 47713498266Sopenharmony_ci * pop3_perform_auth() 47813498266Sopenharmony_ci * 47913498266Sopenharmony_ci * Sends an AUTH command allowing the client to login with the given SASL 48013498266Sopenharmony_ci * authentication mechanism. 48113498266Sopenharmony_ci */ 48213498266Sopenharmony_cistatic CURLcode pop3_perform_auth(struct Curl_easy *data, 48313498266Sopenharmony_ci const char *mech, 48413498266Sopenharmony_ci const struct bufref *initresp) 48513498266Sopenharmony_ci{ 48613498266Sopenharmony_ci CURLcode result = CURLE_OK; 48713498266Sopenharmony_ci struct pop3_conn *pop3c = &data->conn->proto.pop3c; 48813498266Sopenharmony_ci const char *ir = (const char *) Curl_bufref_ptr(initresp); 48913498266Sopenharmony_ci 49013498266Sopenharmony_ci if(ir) { /* AUTH <mech> ...<crlf> */ 49113498266Sopenharmony_ci /* Send the AUTH command with the initial response */ 49213498266Sopenharmony_ci result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, ir); 49313498266Sopenharmony_ci } 49413498266Sopenharmony_ci else { 49513498266Sopenharmony_ci /* Send the AUTH command */ 49613498266Sopenharmony_ci result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s", mech); 49713498266Sopenharmony_ci } 49813498266Sopenharmony_ci 49913498266Sopenharmony_ci return result; 50013498266Sopenharmony_ci} 50113498266Sopenharmony_ci 50213498266Sopenharmony_ci/*********************************************************************** 50313498266Sopenharmony_ci * 50413498266Sopenharmony_ci * pop3_continue_auth() 50513498266Sopenharmony_ci * 50613498266Sopenharmony_ci * Sends SASL continuation data. 50713498266Sopenharmony_ci */ 50813498266Sopenharmony_cistatic CURLcode pop3_continue_auth(struct Curl_easy *data, 50913498266Sopenharmony_ci const char *mech, 51013498266Sopenharmony_ci const struct bufref *resp) 51113498266Sopenharmony_ci{ 51213498266Sopenharmony_ci struct pop3_conn *pop3c = &data->conn->proto.pop3c; 51313498266Sopenharmony_ci 51413498266Sopenharmony_ci (void)mech; 51513498266Sopenharmony_ci 51613498266Sopenharmony_ci return Curl_pp_sendf(data, &pop3c->pp, 51713498266Sopenharmony_ci "%s", (const char *) Curl_bufref_ptr(resp)); 51813498266Sopenharmony_ci} 51913498266Sopenharmony_ci 52013498266Sopenharmony_ci/*********************************************************************** 52113498266Sopenharmony_ci * 52213498266Sopenharmony_ci * pop3_cancel_auth() 52313498266Sopenharmony_ci * 52413498266Sopenharmony_ci * Sends SASL cancellation. 52513498266Sopenharmony_ci */ 52613498266Sopenharmony_cistatic CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech) 52713498266Sopenharmony_ci{ 52813498266Sopenharmony_ci struct pop3_conn *pop3c = &data->conn->proto.pop3c; 52913498266Sopenharmony_ci 53013498266Sopenharmony_ci (void)mech; 53113498266Sopenharmony_ci 53213498266Sopenharmony_ci return Curl_pp_sendf(data, &pop3c->pp, "*"); 53313498266Sopenharmony_ci} 53413498266Sopenharmony_ci 53513498266Sopenharmony_ci/*********************************************************************** 53613498266Sopenharmony_ci * 53713498266Sopenharmony_ci * pop3_perform_authentication() 53813498266Sopenharmony_ci * 53913498266Sopenharmony_ci * Initiates the authentication sequence, with the appropriate SASL 54013498266Sopenharmony_ci * authentication mechanism, falling back to APOP and clear text should a 54113498266Sopenharmony_ci * common mechanism not be available between the client and server. 54213498266Sopenharmony_ci */ 54313498266Sopenharmony_cistatic CURLcode pop3_perform_authentication(struct Curl_easy *data, 54413498266Sopenharmony_ci struct connectdata *conn) 54513498266Sopenharmony_ci{ 54613498266Sopenharmony_ci CURLcode result = CURLE_OK; 54713498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 54813498266Sopenharmony_ci saslprogress progress = SASL_IDLE; 54913498266Sopenharmony_ci 55013498266Sopenharmony_ci /* Check we have enough data to authenticate with and end the 55113498266Sopenharmony_ci connect phase if we don't */ 55213498266Sopenharmony_ci if(!Curl_sasl_can_authenticate(&pop3c->sasl, data)) { 55313498266Sopenharmony_ci pop3_state(data, POP3_STOP); 55413498266Sopenharmony_ci return result; 55513498266Sopenharmony_ci } 55613498266Sopenharmony_ci 55713498266Sopenharmony_ci if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { 55813498266Sopenharmony_ci /* Calculate the SASL login details */ 55913498266Sopenharmony_ci result = Curl_sasl_start(&pop3c->sasl, data, FALSE, &progress); 56013498266Sopenharmony_ci 56113498266Sopenharmony_ci if(!result) 56213498266Sopenharmony_ci if(progress == SASL_INPROGRESS) 56313498266Sopenharmony_ci pop3_state(data, POP3_AUTH); 56413498266Sopenharmony_ci } 56513498266Sopenharmony_ci 56613498266Sopenharmony_ci if(!result && progress == SASL_IDLE) { 56713498266Sopenharmony_ci#ifndef CURL_DISABLE_DIGEST_AUTH 56813498266Sopenharmony_ci if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) 56913498266Sopenharmony_ci /* Perform APOP authentication */ 57013498266Sopenharmony_ci result = pop3_perform_apop(data, conn); 57113498266Sopenharmony_ci else 57213498266Sopenharmony_ci#endif 57313498266Sopenharmony_ci if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) 57413498266Sopenharmony_ci /* Perform clear text authentication */ 57513498266Sopenharmony_ci result = pop3_perform_user(data, conn); 57613498266Sopenharmony_ci else { 57713498266Sopenharmony_ci /* Other mechanisms not supported */ 57813498266Sopenharmony_ci infof(data, "No known authentication mechanisms supported"); 57913498266Sopenharmony_ci result = CURLE_LOGIN_DENIED; 58013498266Sopenharmony_ci } 58113498266Sopenharmony_ci } 58213498266Sopenharmony_ci 58313498266Sopenharmony_ci return result; 58413498266Sopenharmony_ci} 58513498266Sopenharmony_ci 58613498266Sopenharmony_ci/*********************************************************************** 58713498266Sopenharmony_ci * 58813498266Sopenharmony_ci * pop3_perform_command() 58913498266Sopenharmony_ci * 59013498266Sopenharmony_ci * Sends a POP3 based command. 59113498266Sopenharmony_ci */ 59213498266Sopenharmony_cistatic CURLcode pop3_perform_command(struct Curl_easy *data) 59313498266Sopenharmony_ci{ 59413498266Sopenharmony_ci CURLcode result = CURLE_OK; 59513498266Sopenharmony_ci struct connectdata *conn = data->conn; 59613498266Sopenharmony_ci struct POP3 *pop3 = data->req.p.pop3; 59713498266Sopenharmony_ci const char *command = NULL; 59813498266Sopenharmony_ci 59913498266Sopenharmony_ci /* Calculate the default command */ 60013498266Sopenharmony_ci if(pop3->id[0] == '\0' || data->set.list_only) { 60113498266Sopenharmony_ci command = "LIST"; 60213498266Sopenharmony_ci 60313498266Sopenharmony_ci if(pop3->id[0] != '\0') 60413498266Sopenharmony_ci /* Message specific LIST so skip the BODY transfer */ 60513498266Sopenharmony_ci pop3->transfer = PPTRANSFER_INFO; 60613498266Sopenharmony_ci } 60713498266Sopenharmony_ci else 60813498266Sopenharmony_ci command = "RETR"; 60913498266Sopenharmony_ci 61013498266Sopenharmony_ci /* Send the command */ 61113498266Sopenharmony_ci if(pop3->id[0] != '\0') 61213498266Sopenharmony_ci result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s %s", 61313498266Sopenharmony_ci (pop3->custom && pop3->custom[0] != '\0' ? 61413498266Sopenharmony_ci pop3->custom : command), pop3->id); 61513498266Sopenharmony_ci else 61613498266Sopenharmony_ci result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", 61713498266Sopenharmony_ci (pop3->custom && pop3->custom[0] != '\0' ? 61813498266Sopenharmony_ci pop3->custom : command)); 61913498266Sopenharmony_ci 62013498266Sopenharmony_ci if(!result) 62113498266Sopenharmony_ci pop3_state(data, POP3_COMMAND); 62213498266Sopenharmony_ci 62313498266Sopenharmony_ci return result; 62413498266Sopenharmony_ci} 62513498266Sopenharmony_ci 62613498266Sopenharmony_ci/*********************************************************************** 62713498266Sopenharmony_ci * 62813498266Sopenharmony_ci * pop3_perform_quit() 62913498266Sopenharmony_ci * 63013498266Sopenharmony_ci * Performs the quit action prior to sclose() be called. 63113498266Sopenharmony_ci */ 63213498266Sopenharmony_cistatic CURLcode pop3_perform_quit(struct Curl_easy *data, 63313498266Sopenharmony_ci struct connectdata *conn) 63413498266Sopenharmony_ci{ 63513498266Sopenharmony_ci /* Send the QUIT command */ 63613498266Sopenharmony_ci CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "QUIT"); 63713498266Sopenharmony_ci 63813498266Sopenharmony_ci if(!result) 63913498266Sopenharmony_ci pop3_state(data, POP3_QUIT); 64013498266Sopenharmony_ci 64113498266Sopenharmony_ci return result; 64213498266Sopenharmony_ci} 64313498266Sopenharmony_ci 64413498266Sopenharmony_ci/* For the initial server greeting */ 64513498266Sopenharmony_cistatic CURLcode pop3_state_servergreet_resp(struct Curl_easy *data, 64613498266Sopenharmony_ci int pop3code, 64713498266Sopenharmony_ci pop3state instate) 64813498266Sopenharmony_ci{ 64913498266Sopenharmony_ci CURLcode result = CURLE_OK; 65013498266Sopenharmony_ci struct connectdata *conn = data->conn; 65113498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 65213498266Sopenharmony_ci const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf); 65313498266Sopenharmony_ci size_t len = data->conn->proto.pop3c.pp.nfinal; 65413498266Sopenharmony_ci 65513498266Sopenharmony_ci (void)instate; /* no use for this yet */ 65613498266Sopenharmony_ci 65713498266Sopenharmony_ci if(pop3code != '+') { 65813498266Sopenharmony_ci failf(data, "Got unexpected pop3-server response"); 65913498266Sopenharmony_ci result = CURLE_WEIRD_SERVER_REPLY; 66013498266Sopenharmony_ci } 66113498266Sopenharmony_ci else if(len > 3) { 66213498266Sopenharmony_ci /* Does the server support APOP authentication? */ 66313498266Sopenharmony_ci char *lt; 66413498266Sopenharmony_ci char *gt = NULL; 66513498266Sopenharmony_ci 66613498266Sopenharmony_ci /* Look for the APOP timestamp */ 66713498266Sopenharmony_ci lt = memchr(line, '<', len); 66813498266Sopenharmony_ci if(lt) 66913498266Sopenharmony_ci /* search the remainder for '>' */ 67013498266Sopenharmony_ci gt = memchr(lt, '>', len - (lt - line)); 67113498266Sopenharmony_ci if(gt) { 67213498266Sopenharmony_ci /* the length of the timestamp, including the brackets */ 67313498266Sopenharmony_ci size_t timestamplen = gt - lt + 1; 67413498266Sopenharmony_ci char *at = memchr(lt, '@', timestamplen); 67513498266Sopenharmony_ci /* If the timestamp does not contain '@' it is not (as required by 67613498266Sopenharmony_ci RFC-1939) conformant to the RFC-822 message id syntax, and we 67713498266Sopenharmony_ci therefore do not use APOP authentication. */ 67813498266Sopenharmony_ci if(at) { 67913498266Sopenharmony_ci /* dupe the timestamp */ 68013498266Sopenharmony_ci pop3c->apoptimestamp = Curl_memdup0(lt, timestamplen); 68113498266Sopenharmony_ci if(!pop3c->apoptimestamp) 68213498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 68313498266Sopenharmony_ci /* Store the APOP capability */ 68413498266Sopenharmony_ci pop3c->authtypes |= POP3_TYPE_APOP; 68513498266Sopenharmony_ci } 68613498266Sopenharmony_ci } 68713498266Sopenharmony_ci 68813498266Sopenharmony_ci if(!result) 68913498266Sopenharmony_ci result = pop3_perform_capa(data, conn); 69013498266Sopenharmony_ci } 69113498266Sopenharmony_ci 69213498266Sopenharmony_ci return result; 69313498266Sopenharmony_ci} 69413498266Sopenharmony_ci 69513498266Sopenharmony_ci/* For CAPA responses */ 69613498266Sopenharmony_cistatic CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code, 69713498266Sopenharmony_ci pop3state instate) 69813498266Sopenharmony_ci{ 69913498266Sopenharmony_ci CURLcode result = CURLE_OK; 70013498266Sopenharmony_ci struct connectdata *conn = data->conn; 70113498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 70213498266Sopenharmony_ci const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf); 70313498266Sopenharmony_ci size_t len = data->conn->proto.pop3c.pp.nfinal; 70413498266Sopenharmony_ci 70513498266Sopenharmony_ci (void)instate; /* no use for this yet */ 70613498266Sopenharmony_ci 70713498266Sopenharmony_ci /* Do we have a untagged continuation response? */ 70813498266Sopenharmony_ci if(pop3code == '*') { 70913498266Sopenharmony_ci /* Does the server support the STLS capability? */ 71013498266Sopenharmony_ci if(len >= 4 && !memcmp(line, "STLS", 4)) 71113498266Sopenharmony_ci pop3c->tls_supported = TRUE; 71213498266Sopenharmony_ci 71313498266Sopenharmony_ci /* Does the server support clear text authentication? */ 71413498266Sopenharmony_ci else if(len >= 4 && !memcmp(line, "USER", 4)) 71513498266Sopenharmony_ci pop3c->authtypes |= POP3_TYPE_CLEARTEXT; 71613498266Sopenharmony_ci 71713498266Sopenharmony_ci /* Does the server support SASL based authentication? */ 71813498266Sopenharmony_ci else if(len >= 5 && !memcmp(line, "SASL ", 5)) { 71913498266Sopenharmony_ci pop3c->authtypes |= POP3_TYPE_SASL; 72013498266Sopenharmony_ci 72113498266Sopenharmony_ci /* Advance past the SASL keyword */ 72213498266Sopenharmony_ci line += 5; 72313498266Sopenharmony_ci len -= 5; 72413498266Sopenharmony_ci 72513498266Sopenharmony_ci /* Loop through the data line */ 72613498266Sopenharmony_ci for(;;) { 72713498266Sopenharmony_ci size_t llen; 72813498266Sopenharmony_ci size_t wordlen; 72913498266Sopenharmony_ci unsigned short mechbit; 73013498266Sopenharmony_ci 73113498266Sopenharmony_ci while(len && 73213498266Sopenharmony_ci (*line == ' ' || *line == '\t' || 73313498266Sopenharmony_ci *line == '\r' || *line == '\n')) { 73413498266Sopenharmony_ci 73513498266Sopenharmony_ci line++; 73613498266Sopenharmony_ci len--; 73713498266Sopenharmony_ci } 73813498266Sopenharmony_ci 73913498266Sopenharmony_ci if(!len) 74013498266Sopenharmony_ci break; 74113498266Sopenharmony_ci 74213498266Sopenharmony_ci /* Extract the word */ 74313498266Sopenharmony_ci for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && 74413498266Sopenharmony_ci line[wordlen] != '\t' && line[wordlen] != '\r' && 74513498266Sopenharmony_ci line[wordlen] != '\n';) 74613498266Sopenharmony_ci wordlen++; 74713498266Sopenharmony_ci 74813498266Sopenharmony_ci /* Test the word for a matching authentication mechanism */ 74913498266Sopenharmony_ci mechbit = Curl_sasl_decode_mech(line, wordlen, &llen); 75013498266Sopenharmony_ci if(mechbit && llen == wordlen) 75113498266Sopenharmony_ci pop3c->sasl.authmechs |= mechbit; 75213498266Sopenharmony_ci 75313498266Sopenharmony_ci line += wordlen; 75413498266Sopenharmony_ci len -= wordlen; 75513498266Sopenharmony_ci } 75613498266Sopenharmony_ci } 75713498266Sopenharmony_ci } 75813498266Sopenharmony_ci else { 75913498266Sopenharmony_ci /* Clear text is supported when CAPA isn't recognised */ 76013498266Sopenharmony_ci if(pop3code != '+') 76113498266Sopenharmony_ci pop3c->authtypes |= POP3_TYPE_CLEARTEXT; 76213498266Sopenharmony_ci 76313498266Sopenharmony_ci if(!data->set.use_ssl || Curl_conn_is_ssl(conn, FIRSTSOCKET)) 76413498266Sopenharmony_ci result = pop3_perform_authentication(data, conn); 76513498266Sopenharmony_ci else if(pop3code == '+' && pop3c->tls_supported) 76613498266Sopenharmony_ci /* Switch to TLS connection now */ 76713498266Sopenharmony_ci result = pop3_perform_starttls(data, conn); 76813498266Sopenharmony_ci else if(data->set.use_ssl <= CURLUSESSL_TRY) 76913498266Sopenharmony_ci /* Fallback and carry on with authentication */ 77013498266Sopenharmony_ci result = pop3_perform_authentication(data, conn); 77113498266Sopenharmony_ci else { 77213498266Sopenharmony_ci failf(data, "STLS not supported."); 77313498266Sopenharmony_ci result = CURLE_USE_SSL_FAILED; 77413498266Sopenharmony_ci } 77513498266Sopenharmony_ci } 77613498266Sopenharmony_ci 77713498266Sopenharmony_ci return result; 77813498266Sopenharmony_ci} 77913498266Sopenharmony_ci 78013498266Sopenharmony_ci/* For STARTTLS responses */ 78113498266Sopenharmony_cistatic CURLcode pop3_state_starttls_resp(struct Curl_easy *data, 78213498266Sopenharmony_ci struct connectdata *conn, 78313498266Sopenharmony_ci int pop3code, 78413498266Sopenharmony_ci pop3state instate) 78513498266Sopenharmony_ci{ 78613498266Sopenharmony_ci CURLcode result = CURLE_OK; 78713498266Sopenharmony_ci (void)instate; /* no use for this yet */ 78813498266Sopenharmony_ci 78913498266Sopenharmony_ci /* Pipelining in response is forbidden. */ 79013498266Sopenharmony_ci if(data->conn->proto.pop3c.pp.overflow) 79113498266Sopenharmony_ci return CURLE_WEIRD_SERVER_REPLY; 79213498266Sopenharmony_ci 79313498266Sopenharmony_ci if(pop3code != '+') { 79413498266Sopenharmony_ci if(data->set.use_ssl != CURLUSESSL_TRY) { 79513498266Sopenharmony_ci failf(data, "STARTTLS denied"); 79613498266Sopenharmony_ci result = CURLE_USE_SSL_FAILED; 79713498266Sopenharmony_ci } 79813498266Sopenharmony_ci else 79913498266Sopenharmony_ci result = pop3_perform_authentication(data, conn); 80013498266Sopenharmony_ci } 80113498266Sopenharmony_ci else 80213498266Sopenharmony_ci result = pop3_perform_upgrade_tls(data, conn); 80313498266Sopenharmony_ci 80413498266Sopenharmony_ci return result; 80513498266Sopenharmony_ci} 80613498266Sopenharmony_ci 80713498266Sopenharmony_ci/* For SASL authentication responses */ 80813498266Sopenharmony_cistatic CURLcode pop3_state_auth_resp(struct Curl_easy *data, 80913498266Sopenharmony_ci int pop3code, 81013498266Sopenharmony_ci pop3state instate) 81113498266Sopenharmony_ci{ 81213498266Sopenharmony_ci CURLcode result = CURLE_OK; 81313498266Sopenharmony_ci struct connectdata *conn = data->conn; 81413498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 81513498266Sopenharmony_ci saslprogress progress; 81613498266Sopenharmony_ci 81713498266Sopenharmony_ci (void)instate; /* no use for this yet */ 81813498266Sopenharmony_ci 81913498266Sopenharmony_ci result = Curl_sasl_continue(&pop3c->sasl, data, pop3code, &progress); 82013498266Sopenharmony_ci if(!result) 82113498266Sopenharmony_ci switch(progress) { 82213498266Sopenharmony_ci case SASL_DONE: 82313498266Sopenharmony_ci pop3_state(data, POP3_STOP); /* Authenticated */ 82413498266Sopenharmony_ci break; 82513498266Sopenharmony_ci case SASL_IDLE: /* No mechanism left after cancellation */ 82613498266Sopenharmony_ci#ifndef CURL_DISABLE_DIGEST_AUTH 82713498266Sopenharmony_ci if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP) 82813498266Sopenharmony_ci /* Perform APOP authentication */ 82913498266Sopenharmony_ci result = pop3_perform_apop(data, conn); 83013498266Sopenharmony_ci else 83113498266Sopenharmony_ci#endif 83213498266Sopenharmony_ci if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT) 83313498266Sopenharmony_ci /* Perform clear text authentication */ 83413498266Sopenharmony_ci result = pop3_perform_user(data, conn); 83513498266Sopenharmony_ci else { 83613498266Sopenharmony_ci failf(data, "Authentication cancelled"); 83713498266Sopenharmony_ci result = CURLE_LOGIN_DENIED; 83813498266Sopenharmony_ci } 83913498266Sopenharmony_ci break; 84013498266Sopenharmony_ci default: 84113498266Sopenharmony_ci break; 84213498266Sopenharmony_ci } 84313498266Sopenharmony_ci 84413498266Sopenharmony_ci return result; 84513498266Sopenharmony_ci} 84613498266Sopenharmony_ci 84713498266Sopenharmony_ci#ifndef CURL_DISABLE_DIGEST_AUTH 84813498266Sopenharmony_ci/* For APOP responses */ 84913498266Sopenharmony_cistatic CURLcode pop3_state_apop_resp(struct Curl_easy *data, int pop3code, 85013498266Sopenharmony_ci pop3state instate) 85113498266Sopenharmony_ci{ 85213498266Sopenharmony_ci CURLcode result = CURLE_OK; 85313498266Sopenharmony_ci (void)instate; /* no use for this yet */ 85413498266Sopenharmony_ci 85513498266Sopenharmony_ci if(pop3code != '+') { 85613498266Sopenharmony_ci failf(data, "Authentication failed: %d", pop3code); 85713498266Sopenharmony_ci result = CURLE_LOGIN_DENIED; 85813498266Sopenharmony_ci } 85913498266Sopenharmony_ci else 86013498266Sopenharmony_ci /* End of connect phase */ 86113498266Sopenharmony_ci pop3_state(data, POP3_STOP); 86213498266Sopenharmony_ci 86313498266Sopenharmony_ci return result; 86413498266Sopenharmony_ci} 86513498266Sopenharmony_ci#endif 86613498266Sopenharmony_ci 86713498266Sopenharmony_ci/* For USER responses */ 86813498266Sopenharmony_cistatic CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code, 86913498266Sopenharmony_ci pop3state instate) 87013498266Sopenharmony_ci{ 87113498266Sopenharmony_ci CURLcode result = CURLE_OK; 87213498266Sopenharmony_ci struct connectdata *conn = data->conn; 87313498266Sopenharmony_ci (void)instate; /* no use for this yet */ 87413498266Sopenharmony_ci 87513498266Sopenharmony_ci if(pop3code != '+') { 87613498266Sopenharmony_ci failf(data, "Access denied. %c", pop3code); 87713498266Sopenharmony_ci result = CURLE_LOGIN_DENIED; 87813498266Sopenharmony_ci } 87913498266Sopenharmony_ci else 88013498266Sopenharmony_ci /* Send the PASS command */ 88113498266Sopenharmony_ci result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "PASS %s", 88213498266Sopenharmony_ci conn->passwd ? conn->passwd : ""); 88313498266Sopenharmony_ci if(!result) 88413498266Sopenharmony_ci pop3_state(data, POP3_PASS); 88513498266Sopenharmony_ci 88613498266Sopenharmony_ci return result; 88713498266Sopenharmony_ci} 88813498266Sopenharmony_ci 88913498266Sopenharmony_ci/* For PASS responses */ 89013498266Sopenharmony_cistatic CURLcode pop3_state_pass_resp(struct Curl_easy *data, int pop3code, 89113498266Sopenharmony_ci pop3state instate) 89213498266Sopenharmony_ci{ 89313498266Sopenharmony_ci CURLcode result = CURLE_OK; 89413498266Sopenharmony_ci (void)instate; /* no use for this yet */ 89513498266Sopenharmony_ci 89613498266Sopenharmony_ci if(pop3code != '+') { 89713498266Sopenharmony_ci failf(data, "Access denied. %c", pop3code); 89813498266Sopenharmony_ci result = CURLE_LOGIN_DENIED; 89913498266Sopenharmony_ci } 90013498266Sopenharmony_ci else 90113498266Sopenharmony_ci /* End of connect phase */ 90213498266Sopenharmony_ci pop3_state(data, POP3_STOP); 90313498266Sopenharmony_ci 90413498266Sopenharmony_ci return result; 90513498266Sopenharmony_ci} 90613498266Sopenharmony_ci 90713498266Sopenharmony_ci/* For command responses */ 90813498266Sopenharmony_cistatic CURLcode pop3_state_command_resp(struct Curl_easy *data, 90913498266Sopenharmony_ci int pop3code, 91013498266Sopenharmony_ci pop3state instate) 91113498266Sopenharmony_ci{ 91213498266Sopenharmony_ci CURLcode result = CURLE_OK; 91313498266Sopenharmony_ci struct connectdata *conn = data->conn; 91413498266Sopenharmony_ci struct POP3 *pop3 = data->req.p.pop3; 91513498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 91613498266Sopenharmony_ci struct pingpong *pp = &pop3c->pp; 91713498266Sopenharmony_ci 91813498266Sopenharmony_ci (void)instate; /* no use for this yet */ 91913498266Sopenharmony_ci 92013498266Sopenharmony_ci if(pop3code != '+') { 92113498266Sopenharmony_ci pop3_state(data, POP3_STOP); 92213498266Sopenharmony_ci return CURLE_WEIRD_SERVER_REPLY; 92313498266Sopenharmony_ci } 92413498266Sopenharmony_ci 92513498266Sopenharmony_ci /* This 'OK' line ends with a CR LF pair which is the two first bytes of the 92613498266Sopenharmony_ci EOB string so count this is two matching bytes. This is necessary to make 92713498266Sopenharmony_ci the code detect the EOB if the only data than comes now is %2e CR LF like 92813498266Sopenharmony_ci when there is no body to return. */ 92913498266Sopenharmony_ci pop3c->eob = 2; 93013498266Sopenharmony_ci 93113498266Sopenharmony_ci /* But since this initial CR LF pair is not part of the actual body, we set 93213498266Sopenharmony_ci the strip counter here so that these bytes won't be delivered. */ 93313498266Sopenharmony_ci pop3c->strip = 2; 93413498266Sopenharmony_ci 93513498266Sopenharmony_ci if(pop3->transfer == PPTRANSFER_BODY) { 93613498266Sopenharmony_ci /* POP3 download */ 93713498266Sopenharmony_ci Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); 93813498266Sopenharmony_ci 93913498266Sopenharmony_ci if(pp->overflow) { 94013498266Sopenharmony_ci /* The recv buffer contains data that is actually body content so send 94113498266Sopenharmony_ci it as such. Note that there may even be additional "headers" after 94213498266Sopenharmony_ci the body */ 94313498266Sopenharmony_ci 94413498266Sopenharmony_ci /* keep only the overflow */ 94513498266Sopenharmony_ci Curl_dyn_tail(&pp->recvbuf, pp->overflow); 94613498266Sopenharmony_ci pp->nfinal = 0; /* done */ 94713498266Sopenharmony_ci 94813498266Sopenharmony_ci if(!data->req.no_body) { 94913498266Sopenharmony_ci result = Curl_pop3_write(data, Curl_dyn_ptr(&pp->recvbuf), 95013498266Sopenharmony_ci Curl_dyn_len(&pp->recvbuf)); 95113498266Sopenharmony_ci if(result) 95213498266Sopenharmony_ci return result; 95313498266Sopenharmony_ci } 95413498266Sopenharmony_ci 95513498266Sopenharmony_ci /* reset the buffer */ 95613498266Sopenharmony_ci Curl_dyn_reset(&pp->recvbuf); 95713498266Sopenharmony_ci pp->overflow = 0; 95813498266Sopenharmony_ci } 95913498266Sopenharmony_ci } 96013498266Sopenharmony_ci else 96113498266Sopenharmony_ci pp->overflow = 0; 96213498266Sopenharmony_ci 96313498266Sopenharmony_ci /* End of DO phase */ 96413498266Sopenharmony_ci pop3_state(data, POP3_STOP); 96513498266Sopenharmony_ci 96613498266Sopenharmony_ci return result; 96713498266Sopenharmony_ci} 96813498266Sopenharmony_ci 96913498266Sopenharmony_cistatic CURLcode pop3_statemachine(struct Curl_easy *data, 97013498266Sopenharmony_ci struct connectdata *conn) 97113498266Sopenharmony_ci{ 97213498266Sopenharmony_ci CURLcode result = CURLE_OK; 97313498266Sopenharmony_ci curl_socket_t sock = conn->sock[FIRSTSOCKET]; 97413498266Sopenharmony_ci int pop3code; 97513498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 97613498266Sopenharmony_ci struct pingpong *pp = &pop3c->pp; 97713498266Sopenharmony_ci size_t nread = 0; 97813498266Sopenharmony_ci (void)data; 97913498266Sopenharmony_ci 98013498266Sopenharmony_ci /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */ 98113498266Sopenharmony_ci if(pop3c->state == POP3_UPGRADETLS) 98213498266Sopenharmony_ci return pop3_perform_upgrade_tls(data, conn); 98313498266Sopenharmony_ci 98413498266Sopenharmony_ci /* Flush any data that needs to be sent */ 98513498266Sopenharmony_ci if(pp->sendleft) 98613498266Sopenharmony_ci return Curl_pp_flushsend(data, pp); 98713498266Sopenharmony_ci 98813498266Sopenharmony_ci do { 98913498266Sopenharmony_ci /* Read the response from the server */ 99013498266Sopenharmony_ci result = Curl_pp_readresp(data, sock, pp, &pop3code, &nread); 99113498266Sopenharmony_ci if(result) 99213498266Sopenharmony_ci return result; 99313498266Sopenharmony_ci 99413498266Sopenharmony_ci if(!pop3code) 99513498266Sopenharmony_ci break; 99613498266Sopenharmony_ci 99713498266Sopenharmony_ci /* We have now received a full POP3 server response */ 99813498266Sopenharmony_ci switch(pop3c->state) { 99913498266Sopenharmony_ci case POP3_SERVERGREET: 100013498266Sopenharmony_ci result = pop3_state_servergreet_resp(data, pop3code, pop3c->state); 100113498266Sopenharmony_ci break; 100213498266Sopenharmony_ci 100313498266Sopenharmony_ci case POP3_CAPA: 100413498266Sopenharmony_ci result = pop3_state_capa_resp(data, pop3code, pop3c->state); 100513498266Sopenharmony_ci break; 100613498266Sopenharmony_ci 100713498266Sopenharmony_ci case POP3_STARTTLS: 100813498266Sopenharmony_ci result = pop3_state_starttls_resp(data, conn, pop3code, pop3c->state); 100913498266Sopenharmony_ci break; 101013498266Sopenharmony_ci 101113498266Sopenharmony_ci case POP3_AUTH: 101213498266Sopenharmony_ci result = pop3_state_auth_resp(data, pop3code, pop3c->state); 101313498266Sopenharmony_ci break; 101413498266Sopenharmony_ci 101513498266Sopenharmony_ci#ifndef CURL_DISABLE_DIGEST_AUTH 101613498266Sopenharmony_ci case POP3_APOP: 101713498266Sopenharmony_ci result = pop3_state_apop_resp(data, pop3code, pop3c->state); 101813498266Sopenharmony_ci break; 101913498266Sopenharmony_ci#endif 102013498266Sopenharmony_ci 102113498266Sopenharmony_ci case POP3_USER: 102213498266Sopenharmony_ci result = pop3_state_user_resp(data, pop3code, pop3c->state); 102313498266Sopenharmony_ci break; 102413498266Sopenharmony_ci 102513498266Sopenharmony_ci case POP3_PASS: 102613498266Sopenharmony_ci result = pop3_state_pass_resp(data, pop3code, pop3c->state); 102713498266Sopenharmony_ci break; 102813498266Sopenharmony_ci 102913498266Sopenharmony_ci case POP3_COMMAND: 103013498266Sopenharmony_ci result = pop3_state_command_resp(data, pop3code, pop3c->state); 103113498266Sopenharmony_ci break; 103213498266Sopenharmony_ci 103313498266Sopenharmony_ci case POP3_QUIT: 103413498266Sopenharmony_ci pop3_state(data, POP3_STOP); 103513498266Sopenharmony_ci break; 103613498266Sopenharmony_ci 103713498266Sopenharmony_ci default: 103813498266Sopenharmony_ci /* internal error */ 103913498266Sopenharmony_ci pop3_state(data, POP3_STOP); 104013498266Sopenharmony_ci break; 104113498266Sopenharmony_ci } 104213498266Sopenharmony_ci } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp)); 104313498266Sopenharmony_ci 104413498266Sopenharmony_ci return result; 104513498266Sopenharmony_ci} 104613498266Sopenharmony_ci 104713498266Sopenharmony_ci/* Called repeatedly until done from multi.c */ 104813498266Sopenharmony_cistatic CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done) 104913498266Sopenharmony_ci{ 105013498266Sopenharmony_ci CURLcode result = CURLE_OK; 105113498266Sopenharmony_ci struct connectdata *conn = data->conn; 105213498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 105313498266Sopenharmony_ci 105413498266Sopenharmony_ci if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) { 105513498266Sopenharmony_ci bool ssldone = FALSE; 105613498266Sopenharmony_ci result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone); 105713498266Sopenharmony_ci pop3c->ssldone = ssldone; 105813498266Sopenharmony_ci if(result || !pop3c->ssldone) 105913498266Sopenharmony_ci return result; 106013498266Sopenharmony_ci } 106113498266Sopenharmony_ci 106213498266Sopenharmony_ci result = Curl_pp_statemach(data, &pop3c->pp, FALSE, FALSE); 106313498266Sopenharmony_ci *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE; 106413498266Sopenharmony_ci 106513498266Sopenharmony_ci return result; 106613498266Sopenharmony_ci} 106713498266Sopenharmony_ci 106813498266Sopenharmony_cistatic CURLcode pop3_block_statemach(struct Curl_easy *data, 106913498266Sopenharmony_ci struct connectdata *conn, 107013498266Sopenharmony_ci bool disconnecting) 107113498266Sopenharmony_ci{ 107213498266Sopenharmony_ci CURLcode result = CURLE_OK; 107313498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 107413498266Sopenharmony_ci 107513498266Sopenharmony_ci while(pop3c->state != POP3_STOP && !result) 107613498266Sopenharmony_ci result = Curl_pp_statemach(data, &pop3c->pp, TRUE, disconnecting); 107713498266Sopenharmony_ci 107813498266Sopenharmony_ci return result; 107913498266Sopenharmony_ci} 108013498266Sopenharmony_ci 108113498266Sopenharmony_ci/* Allocate and initialize the POP3 struct for the current Curl_easy if 108213498266Sopenharmony_ci required */ 108313498266Sopenharmony_cistatic CURLcode pop3_init(struct Curl_easy *data) 108413498266Sopenharmony_ci{ 108513498266Sopenharmony_ci CURLcode result = CURLE_OK; 108613498266Sopenharmony_ci struct POP3 *pop3; 108713498266Sopenharmony_ci 108813498266Sopenharmony_ci pop3 = data->req.p.pop3 = calloc(1, sizeof(struct POP3)); 108913498266Sopenharmony_ci if(!pop3) 109013498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 109113498266Sopenharmony_ci 109213498266Sopenharmony_ci return result; 109313498266Sopenharmony_ci} 109413498266Sopenharmony_ci 109513498266Sopenharmony_ci/* For the POP3 "protocol connect" and "doing" phases only */ 109613498266Sopenharmony_cistatic int pop3_getsock(struct Curl_easy *data, 109713498266Sopenharmony_ci struct connectdata *conn, curl_socket_t *socks) 109813498266Sopenharmony_ci{ 109913498266Sopenharmony_ci return Curl_pp_getsock(data, &conn->proto.pop3c.pp, socks); 110013498266Sopenharmony_ci} 110113498266Sopenharmony_ci 110213498266Sopenharmony_ci/*********************************************************************** 110313498266Sopenharmony_ci * 110413498266Sopenharmony_ci * pop3_connect() 110513498266Sopenharmony_ci * 110613498266Sopenharmony_ci * This function should do everything that is to be considered a part of the 110713498266Sopenharmony_ci * connection phase. 110813498266Sopenharmony_ci * 110913498266Sopenharmony_ci * The variable 'done' points to will be TRUE if the protocol-layer connect 111013498266Sopenharmony_ci * phase is done when this function returns, or FALSE if not. 111113498266Sopenharmony_ci */ 111213498266Sopenharmony_cistatic CURLcode pop3_connect(struct Curl_easy *data, bool *done) 111313498266Sopenharmony_ci{ 111413498266Sopenharmony_ci CURLcode result = CURLE_OK; 111513498266Sopenharmony_ci struct connectdata *conn = data->conn; 111613498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 111713498266Sopenharmony_ci struct pingpong *pp = &pop3c->pp; 111813498266Sopenharmony_ci 111913498266Sopenharmony_ci *done = FALSE; /* default to not done yet */ 112013498266Sopenharmony_ci 112113498266Sopenharmony_ci /* We always support persistent connections in POP3 */ 112213498266Sopenharmony_ci connkeep(conn, "POP3 default"); 112313498266Sopenharmony_ci 112413498266Sopenharmony_ci PINGPONG_SETUP(pp, pop3_statemachine, pop3_endofresp); 112513498266Sopenharmony_ci 112613498266Sopenharmony_ci /* Set the default preferred authentication type and mechanism */ 112713498266Sopenharmony_ci pop3c->preftype = POP3_TYPE_ANY; 112813498266Sopenharmony_ci Curl_sasl_init(&pop3c->sasl, data, &saslpop3); 112913498266Sopenharmony_ci 113013498266Sopenharmony_ci /* Initialise the pingpong layer */ 113113498266Sopenharmony_ci Curl_pp_init(pp); 113213498266Sopenharmony_ci 113313498266Sopenharmony_ci /* Parse the URL options */ 113413498266Sopenharmony_ci result = pop3_parse_url_options(conn); 113513498266Sopenharmony_ci if(result) 113613498266Sopenharmony_ci return result; 113713498266Sopenharmony_ci 113813498266Sopenharmony_ci /* Start off waiting for the server greeting response */ 113913498266Sopenharmony_ci pop3_state(data, POP3_SERVERGREET); 114013498266Sopenharmony_ci 114113498266Sopenharmony_ci result = pop3_multi_statemach(data, done); 114213498266Sopenharmony_ci 114313498266Sopenharmony_ci return result; 114413498266Sopenharmony_ci} 114513498266Sopenharmony_ci 114613498266Sopenharmony_ci/*********************************************************************** 114713498266Sopenharmony_ci * 114813498266Sopenharmony_ci * pop3_done() 114913498266Sopenharmony_ci * 115013498266Sopenharmony_ci * The DONE function. This does what needs to be done after a single DO has 115113498266Sopenharmony_ci * performed. 115213498266Sopenharmony_ci * 115313498266Sopenharmony_ci * Input argument is already checked for validity. 115413498266Sopenharmony_ci */ 115513498266Sopenharmony_cistatic CURLcode pop3_done(struct Curl_easy *data, CURLcode status, 115613498266Sopenharmony_ci bool premature) 115713498266Sopenharmony_ci{ 115813498266Sopenharmony_ci CURLcode result = CURLE_OK; 115913498266Sopenharmony_ci struct POP3 *pop3 = data->req.p.pop3; 116013498266Sopenharmony_ci 116113498266Sopenharmony_ci (void)premature; 116213498266Sopenharmony_ci 116313498266Sopenharmony_ci if(!pop3) 116413498266Sopenharmony_ci return CURLE_OK; 116513498266Sopenharmony_ci 116613498266Sopenharmony_ci if(status) { 116713498266Sopenharmony_ci connclose(data->conn, "POP3 done with bad status"); 116813498266Sopenharmony_ci result = status; /* use the already set error code */ 116913498266Sopenharmony_ci } 117013498266Sopenharmony_ci 117113498266Sopenharmony_ci /* Cleanup our per-request based variables */ 117213498266Sopenharmony_ci Curl_safefree(pop3->id); 117313498266Sopenharmony_ci Curl_safefree(pop3->custom); 117413498266Sopenharmony_ci 117513498266Sopenharmony_ci /* Clear the transfer mode for the next request */ 117613498266Sopenharmony_ci pop3->transfer = PPTRANSFER_BODY; 117713498266Sopenharmony_ci 117813498266Sopenharmony_ci return result; 117913498266Sopenharmony_ci} 118013498266Sopenharmony_ci 118113498266Sopenharmony_ci/*********************************************************************** 118213498266Sopenharmony_ci * 118313498266Sopenharmony_ci * pop3_perform() 118413498266Sopenharmony_ci * 118513498266Sopenharmony_ci * This is the actual DO function for POP3. Get a message/listing according to 118613498266Sopenharmony_ci * the options previously setup. 118713498266Sopenharmony_ci */ 118813498266Sopenharmony_cistatic CURLcode pop3_perform(struct Curl_easy *data, bool *connected, 118913498266Sopenharmony_ci bool *dophase_done) 119013498266Sopenharmony_ci{ 119113498266Sopenharmony_ci /* This is POP3 and no proxy */ 119213498266Sopenharmony_ci CURLcode result = CURLE_OK; 119313498266Sopenharmony_ci struct POP3 *pop3 = data->req.p.pop3; 119413498266Sopenharmony_ci 119513498266Sopenharmony_ci DEBUGF(infof(data, "DO phase starts")); 119613498266Sopenharmony_ci 119713498266Sopenharmony_ci if(data->req.no_body) { 119813498266Sopenharmony_ci /* Requested no body means no transfer */ 119913498266Sopenharmony_ci pop3->transfer = PPTRANSFER_INFO; 120013498266Sopenharmony_ci } 120113498266Sopenharmony_ci 120213498266Sopenharmony_ci *dophase_done = FALSE; /* not done yet */ 120313498266Sopenharmony_ci 120413498266Sopenharmony_ci /* Start the first command in the DO phase */ 120513498266Sopenharmony_ci result = pop3_perform_command(data); 120613498266Sopenharmony_ci if(result) 120713498266Sopenharmony_ci return result; 120813498266Sopenharmony_ci 120913498266Sopenharmony_ci /* Run the state-machine */ 121013498266Sopenharmony_ci result = pop3_multi_statemach(data, dophase_done); 121113498266Sopenharmony_ci *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET); 121213498266Sopenharmony_ci 121313498266Sopenharmony_ci if(*dophase_done) 121413498266Sopenharmony_ci DEBUGF(infof(data, "DO phase is complete")); 121513498266Sopenharmony_ci 121613498266Sopenharmony_ci return result; 121713498266Sopenharmony_ci} 121813498266Sopenharmony_ci 121913498266Sopenharmony_ci/*********************************************************************** 122013498266Sopenharmony_ci * 122113498266Sopenharmony_ci * pop3_do() 122213498266Sopenharmony_ci * 122313498266Sopenharmony_ci * This function is registered as 'curl_do' function. It decodes the path 122413498266Sopenharmony_ci * parts etc as a wrapper to the actual DO function (pop3_perform). 122513498266Sopenharmony_ci * 122613498266Sopenharmony_ci * The input argument is already checked for validity. 122713498266Sopenharmony_ci */ 122813498266Sopenharmony_cistatic CURLcode pop3_do(struct Curl_easy *data, bool *done) 122913498266Sopenharmony_ci{ 123013498266Sopenharmony_ci CURLcode result = CURLE_OK; 123113498266Sopenharmony_ci *done = FALSE; /* default to false */ 123213498266Sopenharmony_ci 123313498266Sopenharmony_ci /* Parse the URL path */ 123413498266Sopenharmony_ci result = pop3_parse_url_path(data); 123513498266Sopenharmony_ci if(result) 123613498266Sopenharmony_ci return result; 123713498266Sopenharmony_ci 123813498266Sopenharmony_ci /* Parse the custom request */ 123913498266Sopenharmony_ci result = pop3_parse_custom_request(data); 124013498266Sopenharmony_ci if(result) 124113498266Sopenharmony_ci return result; 124213498266Sopenharmony_ci 124313498266Sopenharmony_ci result = pop3_regular_transfer(data, done); 124413498266Sopenharmony_ci 124513498266Sopenharmony_ci return result; 124613498266Sopenharmony_ci} 124713498266Sopenharmony_ci 124813498266Sopenharmony_ci/*********************************************************************** 124913498266Sopenharmony_ci * 125013498266Sopenharmony_ci * pop3_disconnect() 125113498266Sopenharmony_ci * 125213498266Sopenharmony_ci * Disconnect from an POP3 server. Cleanup protocol-specific per-connection 125313498266Sopenharmony_ci * resources. BLOCKING. 125413498266Sopenharmony_ci */ 125513498266Sopenharmony_cistatic CURLcode pop3_disconnect(struct Curl_easy *data, 125613498266Sopenharmony_ci struct connectdata *conn, bool dead_connection) 125713498266Sopenharmony_ci{ 125813498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 125913498266Sopenharmony_ci (void)data; 126013498266Sopenharmony_ci 126113498266Sopenharmony_ci /* We cannot send quit unconditionally. If this connection is stale or 126213498266Sopenharmony_ci bad in any way, sending quit and waiting around here will make the 126313498266Sopenharmony_ci disconnect wait in vain and cause more problems than we need to. */ 126413498266Sopenharmony_ci 126513498266Sopenharmony_ci if(!dead_connection && conn->bits.protoconnstart) { 126613498266Sopenharmony_ci if(!pop3_perform_quit(data, conn)) 126713498266Sopenharmony_ci (void)pop3_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */ 126813498266Sopenharmony_ci } 126913498266Sopenharmony_ci 127013498266Sopenharmony_ci /* Disconnect from the server */ 127113498266Sopenharmony_ci Curl_pp_disconnect(&pop3c->pp); 127213498266Sopenharmony_ci 127313498266Sopenharmony_ci /* Cleanup the SASL module */ 127413498266Sopenharmony_ci Curl_sasl_cleanup(conn, pop3c->sasl.authused); 127513498266Sopenharmony_ci 127613498266Sopenharmony_ci /* Cleanup our connection based variables */ 127713498266Sopenharmony_ci Curl_safefree(pop3c->apoptimestamp); 127813498266Sopenharmony_ci 127913498266Sopenharmony_ci return CURLE_OK; 128013498266Sopenharmony_ci} 128113498266Sopenharmony_ci 128213498266Sopenharmony_ci/* Call this when the DO phase has completed */ 128313498266Sopenharmony_cistatic CURLcode pop3_dophase_done(struct Curl_easy *data, bool connected) 128413498266Sopenharmony_ci{ 128513498266Sopenharmony_ci (void)data; 128613498266Sopenharmony_ci (void)connected; 128713498266Sopenharmony_ci 128813498266Sopenharmony_ci return CURLE_OK; 128913498266Sopenharmony_ci} 129013498266Sopenharmony_ci 129113498266Sopenharmony_ci/* Called from multi.c while DOing */ 129213498266Sopenharmony_cistatic CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done) 129313498266Sopenharmony_ci{ 129413498266Sopenharmony_ci CURLcode result = pop3_multi_statemach(data, dophase_done); 129513498266Sopenharmony_ci 129613498266Sopenharmony_ci if(result) 129713498266Sopenharmony_ci DEBUGF(infof(data, "DO phase failed")); 129813498266Sopenharmony_ci else if(*dophase_done) { 129913498266Sopenharmony_ci result = pop3_dophase_done(data, FALSE /* not connected */); 130013498266Sopenharmony_ci 130113498266Sopenharmony_ci DEBUGF(infof(data, "DO phase is complete")); 130213498266Sopenharmony_ci } 130313498266Sopenharmony_ci 130413498266Sopenharmony_ci return result; 130513498266Sopenharmony_ci} 130613498266Sopenharmony_ci 130713498266Sopenharmony_ci/*********************************************************************** 130813498266Sopenharmony_ci * 130913498266Sopenharmony_ci * pop3_regular_transfer() 131013498266Sopenharmony_ci * 131113498266Sopenharmony_ci * The input argument is already checked for validity. 131213498266Sopenharmony_ci * 131313498266Sopenharmony_ci * Performs all commands done before a regular transfer between a local and a 131413498266Sopenharmony_ci * remote host. 131513498266Sopenharmony_ci */ 131613498266Sopenharmony_cistatic CURLcode pop3_regular_transfer(struct Curl_easy *data, 131713498266Sopenharmony_ci bool *dophase_done) 131813498266Sopenharmony_ci{ 131913498266Sopenharmony_ci CURLcode result = CURLE_OK; 132013498266Sopenharmony_ci bool connected = FALSE; 132113498266Sopenharmony_ci 132213498266Sopenharmony_ci /* Make sure size is unknown at this point */ 132313498266Sopenharmony_ci data->req.size = -1; 132413498266Sopenharmony_ci 132513498266Sopenharmony_ci /* Set the progress data */ 132613498266Sopenharmony_ci Curl_pgrsSetUploadCounter(data, 0); 132713498266Sopenharmony_ci Curl_pgrsSetDownloadCounter(data, 0); 132813498266Sopenharmony_ci Curl_pgrsSetUploadSize(data, -1); 132913498266Sopenharmony_ci Curl_pgrsSetDownloadSize(data, -1); 133013498266Sopenharmony_ci 133113498266Sopenharmony_ci /* Carry out the perform */ 133213498266Sopenharmony_ci result = pop3_perform(data, &connected, dophase_done); 133313498266Sopenharmony_ci 133413498266Sopenharmony_ci /* Perform post DO phase operations if necessary */ 133513498266Sopenharmony_ci if(!result && *dophase_done) 133613498266Sopenharmony_ci result = pop3_dophase_done(data, connected); 133713498266Sopenharmony_ci 133813498266Sopenharmony_ci return result; 133913498266Sopenharmony_ci} 134013498266Sopenharmony_ci 134113498266Sopenharmony_cistatic CURLcode pop3_setup_connection(struct Curl_easy *data, 134213498266Sopenharmony_ci struct connectdata *conn) 134313498266Sopenharmony_ci{ 134413498266Sopenharmony_ci /* Initialise the POP3 layer */ 134513498266Sopenharmony_ci CURLcode result = pop3_init(data); 134613498266Sopenharmony_ci if(result) 134713498266Sopenharmony_ci return result; 134813498266Sopenharmony_ci 134913498266Sopenharmony_ci /* Clear the TLS upgraded flag */ 135013498266Sopenharmony_ci conn->bits.tls_upgraded = FALSE; 135113498266Sopenharmony_ci 135213498266Sopenharmony_ci return CURLE_OK; 135313498266Sopenharmony_ci} 135413498266Sopenharmony_ci 135513498266Sopenharmony_ci/*********************************************************************** 135613498266Sopenharmony_ci * 135713498266Sopenharmony_ci * pop3_parse_url_options() 135813498266Sopenharmony_ci * 135913498266Sopenharmony_ci * Parse the URL login options. 136013498266Sopenharmony_ci */ 136113498266Sopenharmony_cistatic CURLcode pop3_parse_url_options(struct connectdata *conn) 136213498266Sopenharmony_ci{ 136313498266Sopenharmony_ci CURLcode result = CURLE_OK; 136413498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 136513498266Sopenharmony_ci const char *ptr = conn->options; 136613498266Sopenharmony_ci 136713498266Sopenharmony_ci while(!result && ptr && *ptr) { 136813498266Sopenharmony_ci const char *key = ptr; 136913498266Sopenharmony_ci const char *value; 137013498266Sopenharmony_ci 137113498266Sopenharmony_ci while(*ptr && *ptr != '=') 137213498266Sopenharmony_ci ptr++; 137313498266Sopenharmony_ci 137413498266Sopenharmony_ci value = ptr + 1; 137513498266Sopenharmony_ci 137613498266Sopenharmony_ci while(*ptr && *ptr != ';') 137713498266Sopenharmony_ci ptr++; 137813498266Sopenharmony_ci 137913498266Sopenharmony_ci if(strncasecompare(key, "AUTH=", 5)) { 138013498266Sopenharmony_ci result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, 138113498266Sopenharmony_ci value, ptr - value); 138213498266Sopenharmony_ci 138313498266Sopenharmony_ci if(result && strncasecompare(value, "+APOP", ptr - value)) { 138413498266Sopenharmony_ci pop3c->preftype = POP3_TYPE_APOP; 138513498266Sopenharmony_ci pop3c->sasl.prefmech = SASL_AUTH_NONE; 138613498266Sopenharmony_ci result = CURLE_OK; 138713498266Sopenharmony_ci } 138813498266Sopenharmony_ci } 138913498266Sopenharmony_ci else 139013498266Sopenharmony_ci result = CURLE_URL_MALFORMAT; 139113498266Sopenharmony_ci 139213498266Sopenharmony_ci if(*ptr == ';') 139313498266Sopenharmony_ci ptr++; 139413498266Sopenharmony_ci } 139513498266Sopenharmony_ci 139613498266Sopenharmony_ci if(pop3c->preftype != POP3_TYPE_APOP) 139713498266Sopenharmony_ci switch(pop3c->sasl.prefmech) { 139813498266Sopenharmony_ci case SASL_AUTH_NONE: 139913498266Sopenharmony_ci pop3c->preftype = POP3_TYPE_NONE; 140013498266Sopenharmony_ci break; 140113498266Sopenharmony_ci case SASL_AUTH_DEFAULT: 140213498266Sopenharmony_ci pop3c->preftype = POP3_TYPE_ANY; 140313498266Sopenharmony_ci break; 140413498266Sopenharmony_ci default: 140513498266Sopenharmony_ci pop3c->preftype = POP3_TYPE_SASL; 140613498266Sopenharmony_ci break; 140713498266Sopenharmony_ci } 140813498266Sopenharmony_ci 140913498266Sopenharmony_ci return result; 141013498266Sopenharmony_ci} 141113498266Sopenharmony_ci 141213498266Sopenharmony_ci/*********************************************************************** 141313498266Sopenharmony_ci * 141413498266Sopenharmony_ci * pop3_parse_url_path() 141513498266Sopenharmony_ci * 141613498266Sopenharmony_ci * Parse the URL path into separate path components. 141713498266Sopenharmony_ci */ 141813498266Sopenharmony_cistatic CURLcode pop3_parse_url_path(struct Curl_easy *data) 141913498266Sopenharmony_ci{ 142013498266Sopenharmony_ci /* The POP3 struct is already initialised in pop3_connect() */ 142113498266Sopenharmony_ci struct POP3 *pop3 = data->req.p.pop3; 142213498266Sopenharmony_ci const char *path = &data->state.up.path[1]; /* skip leading path */ 142313498266Sopenharmony_ci 142413498266Sopenharmony_ci /* URL decode the path for the message ID */ 142513498266Sopenharmony_ci return Curl_urldecode(path, 0, &pop3->id, NULL, REJECT_CTRL); 142613498266Sopenharmony_ci} 142713498266Sopenharmony_ci 142813498266Sopenharmony_ci/*********************************************************************** 142913498266Sopenharmony_ci * 143013498266Sopenharmony_ci * pop3_parse_custom_request() 143113498266Sopenharmony_ci * 143213498266Sopenharmony_ci * Parse the custom request. 143313498266Sopenharmony_ci */ 143413498266Sopenharmony_cistatic CURLcode pop3_parse_custom_request(struct Curl_easy *data) 143513498266Sopenharmony_ci{ 143613498266Sopenharmony_ci CURLcode result = CURLE_OK; 143713498266Sopenharmony_ci struct POP3 *pop3 = data->req.p.pop3; 143813498266Sopenharmony_ci const char *custom = data->set.str[STRING_CUSTOMREQUEST]; 143913498266Sopenharmony_ci 144013498266Sopenharmony_ci /* URL decode the custom request */ 144113498266Sopenharmony_ci if(custom) 144213498266Sopenharmony_ci result = Curl_urldecode(custom, 0, &pop3->custom, NULL, REJECT_CTRL); 144313498266Sopenharmony_ci 144413498266Sopenharmony_ci return result; 144513498266Sopenharmony_ci} 144613498266Sopenharmony_ci 144713498266Sopenharmony_ci/*********************************************************************** 144813498266Sopenharmony_ci * 144913498266Sopenharmony_ci * Curl_pop3_write() 145013498266Sopenharmony_ci * 145113498266Sopenharmony_ci * This function scans the body after the end-of-body and writes everything 145213498266Sopenharmony_ci * until the end is found. 145313498266Sopenharmony_ci */ 145413498266Sopenharmony_ciCURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread) 145513498266Sopenharmony_ci{ 145613498266Sopenharmony_ci /* This code could be made into a special function in the handler struct */ 145713498266Sopenharmony_ci CURLcode result = CURLE_OK; 145813498266Sopenharmony_ci struct SingleRequest *k = &data->req; 145913498266Sopenharmony_ci struct connectdata *conn = data->conn; 146013498266Sopenharmony_ci struct pop3_conn *pop3c = &conn->proto.pop3c; 146113498266Sopenharmony_ci bool strip_dot = FALSE; 146213498266Sopenharmony_ci size_t last = 0; 146313498266Sopenharmony_ci size_t i; 146413498266Sopenharmony_ci 146513498266Sopenharmony_ci /* Search through the buffer looking for the end-of-body marker which is 146613498266Sopenharmony_ci 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches 146713498266Sopenharmony_ci the eob so the server will have prefixed it with an extra dot which we 146813498266Sopenharmony_ci need to strip out. Additionally the marker could of course be spread out 146913498266Sopenharmony_ci over 5 different data chunks. */ 147013498266Sopenharmony_ci for(i = 0; i < nread; i++) { 147113498266Sopenharmony_ci size_t prev = pop3c->eob; 147213498266Sopenharmony_ci 147313498266Sopenharmony_ci switch(str[i]) { 147413498266Sopenharmony_ci case 0x0d: 147513498266Sopenharmony_ci if(pop3c->eob == 0) { 147613498266Sopenharmony_ci pop3c->eob++; 147713498266Sopenharmony_ci 147813498266Sopenharmony_ci if(i) { 147913498266Sopenharmony_ci /* Write out the body part that didn't match */ 148013498266Sopenharmony_ci result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last], 148113498266Sopenharmony_ci i - last); 148213498266Sopenharmony_ci 148313498266Sopenharmony_ci if(result) 148413498266Sopenharmony_ci return result; 148513498266Sopenharmony_ci 148613498266Sopenharmony_ci last = i; 148713498266Sopenharmony_ci } 148813498266Sopenharmony_ci } 148913498266Sopenharmony_ci else if(pop3c->eob == 3) 149013498266Sopenharmony_ci pop3c->eob++; 149113498266Sopenharmony_ci else 149213498266Sopenharmony_ci /* If the character match wasn't at position 0 or 3 then restart the 149313498266Sopenharmony_ci pattern matching */ 149413498266Sopenharmony_ci pop3c->eob = 1; 149513498266Sopenharmony_ci break; 149613498266Sopenharmony_ci 149713498266Sopenharmony_ci case 0x0a: 149813498266Sopenharmony_ci if(pop3c->eob == 1 || pop3c->eob == 4) 149913498266Sopenharmony_ci pop3c->eob++; 150013498266Sopenharmony_ci else 150113498266Sopenharmony_ci /* If the character match wasn't at position 1 or 4 then start the 150213498266Sopenharmony_ci search again */ 150313498266Sopenharmony_ci pop3c->eob = 0; 150413498266Sopenharmony_ci break; 150513498266Sopenharmony_ci 150613498266Sopenharmony_ci case 0x2e: 150713498266Sopenharmony_ci if(pop3c->eob == 2) 150813498266Sopenharmony_ci pop3c->eob++; 150913498266Sopenharmony_ci else if(pop3c->eob == 3) { 151013498266Sopenharmony_ci /* We have an extra dot after the CRLF which we need to strip off */ 151113498266Sopenharmony_ci strip_dot = TRUE; 151213498266Sopenharmony_ci pop3c->eob = 0; 151313498266Sopenharmony_ci } 151413498266Sopenharmony_ci else 151513498266Sopenharmony_ci /* If the character match wasn't at position 2 then start the search 151613498266Sopenharmony_ci again */ 151713498266Sopenharmony_ci pop3c->eob = 0; 151813498266Sopenharmony_ci break; 151913498266Sopenharmony_ci 152013498266Sopenharmony_ci default: 152113498266Sopenharmony_ci pop3c->eob = 0; 152213498266Sopenharmony_ci break; 152313498266Sopenharmony_ci } 152413498266Sopenharmony_ci 152513498266Sopenharmony_ci /* Did we have a partial match which has subsequently failed? */ 152613498266Sopenharmony_ci if(prev && prev >= pop3c->eob) { 152713498266Sopenharmony_ci /* Strip can only be non-zero for the very first mismatch after CRLF 152813498266Sopenharmony_ci and then both prev and strip are equal and nothing will be output 152913498266Sopenharmony_ci below */ 153013498266Sopenharmony_ci while(prev && pop3c->strip) { 153113498266Sopenharmony_ci prev--; 153213498266Sopenharmony_ci pop3c->strip--; 153313498266Sopenharmony_ci } 153413498266Sopenharmony_ci 153513498266Sopenharmony_ci if(prev) { 153613498266Sopenharmony_ci /* If the partial match was the CRLF and dot then only write the CRLF 153713498266Sopenharmony_ci as the server would have inserted the dot */ 153813498266Sopenharmony_ci if(strip_dot && prev - 1 > 0) { 153913498266Sopenharmony_ci result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB, 154013498266Sopenharmony_ci prev - 1); 154113498266Sopenharmony_ci } 154213498266Sopenharmony_ci else if(!strip_dot) { 154313498266Sopenharmony_ci result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB, 154413498266Sopenharmony_ci prev); 154513498266Sopenharmony_ci } 154613498266Sopenharmony_ci else { 154713498266Sopenharmony_ci result = CURLE_OK; 154813498266Sopenharmony_ci } 154913498266Sopenharmony_ci 155013498266Sopenharmony_ci if(result) 155113498266Sopenharmony_ci return result; 155213498266Sopenharmony_ci 155313498266Sopenharmony_ci last = i; 155413498266Sopenharmony_ci strip_dot = FALSE; 155513498266Sopenharmony_ci } 155613498266Sopenharmony_ci } 155713498266Sopenharmony_ci } 155813498266Sopenharmony_ci 155913498266Sopenharmony_ci if(pop3c->eob == POP3_EOB_LEN) { 156013498266Sopenharmony_ci /* We have a full match so the transfer is done, however we must transfer 156113498266Sopenharmony_ci the CRLF at the start of the EOB as this is considered to be part of the 156213498266Sopenharmony_ci message as per RFC-1939, sect. 3 */ 156313498266Sopenharmony_ci result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB, 2); 156413498266Sopenharmony_ci 156513498266Sopenharmony_ci k->keepon &= ~KEEP_RECV; 156613498266Sopenharmony_ci pop3c->eob = 0; 156713498266Sopenharmony_ci 156813498266Sopenharmony_ci return result; 156913498266Sopenharmony_ci } 157013498266Sopenharmony_ci 157113498266Sopenharmony_ci if(pop3c->eob) 157213498266Sopenharmony_ci /* While EOB is matching nothing should be output */ 157313498266Sopenharmony_ci return CURLE_OK; 157413498266Sopenharmony_ci 157513498266Sopenharmony_ci if(nread - last) { 157613498266Sopenharmony_ci result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last], 157713498266Sopenharmony_ci nread - last); 157813498266Sopenharmony_ci } 157913498266Sopenharmony_ci 158013498266Sopenharmony_ci return result; 158113498266Sopenharmony_ci} 158213498266Sopenharmony_ci 158313498266Sopenharmony_ci#endif /* CURL_DISABLE_POP3 */ 1584