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