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 * RFC2195 CRAM-MD5 authentication
2413498266Sopenharmony_ci * RFC2595 Using TLS with IMAP, POP3 and ACAP
2513498266Sopenharmony_ci * RFC2831 DIGEST-MD5 authentication
2613498266Sopenharmony_ci * RFC3501 IMAPv4 protocol
2713498266Sopenharmony_ci * RFC4422 Simple Authentication and Security Layer (SASL)
2813498266Sopenharmony_ci * RFC4616 PLAIN authentication
2913498266Sopenharmony_ci * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
3013498266Sopenharmony_ci * RFC4959 IMAP Extension for SASL Initial Client Response
3113498266Sopenharmony_ci * RFC5092 IMAP URL Scheme
3213498266Sopenharmony_ci * RFC6749 OAuth 2.0 Authorization Framework
3313498266Sopenharmony_ci * RFC8314 Use of TLS for Email Submission and Access
3413498266Sopenharmony_ci * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
3513498266Sopenharmony_ci *
3613498266Sopenharmony_ci ***************************************************************************/
3713498266Sopenharmony_ci
3813498266Sopenharmony_ci#include "curl_setup.h"
3913498266Sopenharmony_ci
4013498266Sopenharmony_ci#ifndef CURL_DISABLE_IMAP
4113498266Sopenharmony_ci
4213498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
4313498266Sopenharmony_ci#include <netinet/in.h>
4413498266Sopenharmony_ci#endif
4513498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H
4613498266Sopenharmony_ci#include <arpa/inet.h>
4713498266Sopenharmony_ci#endif
4813498266Sopenharmony_ci#ifdef HAVE_NETDB_H
4913498266Sopenharmony_ci#include <netdb.h>
5013498266Sopenharmony_ci#endif
5113498266Sopenharmony_ci#ifdef __VMS
5213498266Sopenharmony_ci#include <in.h>
5313498266Sopenharmony_ci#include <inet.h>
5413498266Sopenharmony_ci#endif
5513498266Sopenharmony_ci
5613498266Sopenharmony_ci#include <curl/curl.h>
5713498266Sopenharmony_ci#include "urldata.h"
5813498266Sopenharmony_ci#include "sendf.h"
5913498266Sopenharmony_ci#include "hostip.h"
6013498266Sopenharmony_ci#include "progress.h"
6113498266Sopenharmony_ci#include "transfer.h"
6213498266Sopenharmony_ci#include "escape.h"
6313498266Sopenharmony_ci#include "http.h" /* for HTTP proxy tunnel stuff */
6413498266Sopenharmony_ci#include "socks.h"
6513498266Sopenharmony_ci#include "imap.h"
6613498266Sopenharmony_ci#include "mime.h"
6713498266Sopenharmony_ci#include "strtoofft.h"
6813498266Sopenharmony_ci#include "strcase.h"
6913498266Sopenharmony_ci#include "vtls/vtls.h"
7013498266Sopenharmony_ci#include "cfilters.h"
7113498266Sopenharmony_ci#include "connect.h"
7213498266Sopenharmony_ci#include "select.h"
7313498266Sopenharmony_ci#include "multiif.h"
7413498266Sopenharmony_ci#include "url.h"
7513498266Sopenharmony_ci#include "bufref.h"
7613498266Sopenharmony_ci#include "curl_sasl.h"
7713498266Sopenharmony_ci#include "warnless.h"
7813498266Sopenharmony_ci#include "curl_ctype.h"
7913498266Sopenharmony_ci
8013498266Sopenharmony_ci/* The last 3 #include files should be in this order */
8113498266Sopenharmony_ci#include "curl_printf.h"
8213498266Sopenharmony_ci#include "curl_memory.h"
8313498266Sopenharmony_ci#include "memdebug.h"
8413498266Sopenharmony_ci
8513498266Sopenharmony_ci/* Local API functions */
8613498266Sopenharmony_cistatic CURLcode imap_regular_transfer(struct Curl_easy *data, bool *done);
8713498266Sopenharmony_cistatic CURLcode imap_do(struct Curl_easy *data, bool *done);
8813498266Sopenharmony_cistatic CURLcode imap_done(struct Curl_easy *data, CURLcode status,
8913498266Sopenharmony_ci                          bool premature);
9013498266Sopenharmony_cistatic CURLcode imap_connect(struct Curl_easy *data, bool *done);
9113498266Sopenharmony_cistatic CURLcode imap_disconnect(struct Curl_easy *data,
9213498266Sopenharmony_ci                                struct connectdata *conn, bool dead);
9313498266Sopenharmony_cistatic CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done);
9413498266Sopenharmony_cistatic int imap_getsock(struct Curl_easy *data, struct connectdata *conn,
9513498266Sopenharmony_ci                        curl_socket_t *socks);
9613498266Sopenharmony_cistatic CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done);
9713498266Sopenharmony_cistatic CURLcode imap_setup_connection(struct Curl_easy *data,
9813498266Sopenharmony_ci                                      struct connectdata *conn);
9913498266Sopenharmony_cistatic char *imap_atom(const char *str, bool escape_only);
10013498266Sopenharmony_cistatic CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
10113498266Sopenharmony_ci  CURL_PRINTF(2, 3);
10213498266Sopenharmony_cistatic CURLcode imap_parse_url_options(struct connectdata *conn);
10313498266Sopenharmony_cistatic CURLcode imap_parse_url_path(struct Curl_easy *data);
10413498266Sopenharmony_cistatic CURLcode imap_parse_custom_request(struct Curl_easy *data);
10513498266Sopenharmony_cistatic CURLcode imap_perform_authenticate(struct Curl_easy *data,
10613498266Sopenharmony_ci                                          const char *mech,
10713498266Sopenharmony_ci                                          const struct bufref *initresp);
10813498266Sopenharmony_cistatic CURLcode imap_continue_authenticate(struct Curl_easy *data,
10913498266Sopenharmony_ci                                           const char *mech,
11013498266Sopenharmony_ci                                           const struct bufref *resp);
11113498266Sopenharmony_cistatic CURLcode imap_cancel_authenticate(struct Curl_easy *data,
11213498266Sopenharmony_ci                                         const char *mech);
11313498266Sopenharmony_cistatic CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out);
11413498266Sopenharmony_ci
11513498266Sopenharmony_ci/*
11613498266Sopenharmony_ci * IMAP protocol handler.
11713498266Sopenharmony_ci */
11813498266Sopenharmony_ci
11913498266Sopenharmony_ciconst struct Curl_handler Curl_handler_imap = {
12013498266Sopenharmony_ci  "IMAP",                           /* scheme */
12113498266Sopenharmony_ci  imap_setup_connection,            /* setup_connection */
12213498266Sopenharmony_ci  imap_do,                          /* do_it */
12313498266Sopenharmony_ci  imap_done,                        /* done */
12413498266Sopenharmony_ci  ZERO_NULL,                        /* do_more */
12513498266Sopenharmony_ci  imap_connect,                     /* connect_it */
12613498266Sopenharmony_ci  imap_multi_statemach,             /* connecting */
12713498266Sopenharmony_ci  imap_doing,                       /* doing */
12813498266Sopenharmony_ci  imap_getsock,                     /* proto_getsock */
12913498266Sopenharmony_ci  imap_getsock,                     /* doing_getsock */
13013498266Sopenharmony_ci  ZERO_NULL,                        /* domore_getsock */
13113498266Sopenharmony_ci  ZERO_NULL,                        /* perform_getsock */
13213498266Sopenharmony_ci  imap_disconnect,                  /* disconnect */
13313498266Sopenharmony_ci  ZERO_NULL,                        /* write_resp */
13413498266Sopenharmony_ci  ZERO_NULL,                        /* connection_check */
13513498266Sopenharmony_ci  ZERO_NULL,                        /* attach connection */
13613498266Sopenharmony_ci  PORT_IMAP,                        /* defport */
13713498266Sopenharmony_ci  CURLPROTO_IMAP,                   /* protocol */
13813498266Sopenharmony_ci  CURLPROTO_IMAP,                   /* family */
13913498266Sopenharmony_ci  PROTOPT_CLOSEACTION|              /* flags */
14013498266Sopenharmony_ci  PROTOPT_URLOPTIONS
14113498266Sopenharmony_ci};
14213498266Sopenharmony_ci
14313498266Sopenharmony_ci#ifdef USE_SSL
14413498266Sopenharmony_ci/*
14513498266Sopenharmony_ci * IMAPS protocol handler.
14613498266Sopenharmony_ci */
14713498266Sopenharmony_ci
14813498266Sopenharmony_ciconst struct Curl_handler Curl_handler_imaps = {
14913498266Sopenharmony_ci  "IMAPS",                          /* scheme */
15013498266Sopenharmony_ci  imap_setup_connection,            /* setup_connection */
15113498266Sopenharmony_ci  imap_do,                          /* do_it */
15213498266Sopenharmony_ci  imap_done,                        /* done */
15313498266Sopenharmony_ci  ZERO_NULL,                        /* do_more */
15413498266Sopenharmony_ci  imap_connect,                     /* connect_it */
15513498266Sopenharmony_ci  imap_multi_statemach,             /* connecting */
15613498266Sopenharmony_ci  imap_doing,                       /* doing */
15713498266Sopenharmony_ci  imap_getsock,                     /* proto_getsock */
15813498266Sopenharmony_ci  imap_getsock,                     /* doing_getsock */
15913498266Sopenharmony_ci  ZERO_NULL,                        /* domore_getsock */
16013498266Sopenharmony_ci  ZERO_NULL,                        /* perform_getsock */
16113498266Sopenharmony_ci  imap_disconnect,                  /* disconnect */
16213498266Sopenharmony_ci  ZERO_NULL,                        /* write_resp */
16313498266Sopenharmony_ci  ZERO_NULL,                        /* connection_check */
16413498266Sopenharmony_ci  ZERO_NULL,                        /* attach connection */
16513498266Sopenharmony_ci  PORT_IMAPS,                       /* defport */
16613498266Sopenharmony_ci  CURLPROTO_IMAPS,                  /* protocol */
16713498266Sopenharmony_ci  CURLPROTO_IMAP,                   /* family */
16813498266Sopenharmony_ci  PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
16913498266Sopenharmony_ci  PROTOPT_URLOPTIONS
17013498266Sopenharmony_ci};
17113498266Sopenharmony_ci#endif
17213498266Sopenharmony_ci
17313498266Sopenharmony_ci#define IMAP_RESP_OK       1
17413498266Sopenharmony_ci#define IMAP_RESP_NOT_OK   2
17513498266Sopenharmony_ci#define IMAP_RESP_PREAUTH  3
17613498266Sopenharmony_ci
17713498266Sopenharmony_ci/* SASL parameters for the imap protocol */
17813498266Sopenharmony_cistatic const struct SASLproto saslimap = {
17913498266Sopenharmony_ci  "imap",                     /* The service name */
18013498266Sopenharmony_ci  imap_perform_authenticate,  /* Send authentication command */
18113498266Sopenharmony_ci  imap_continue_authenticate, /* Send authentication continuation */
18213498266Sopenharmony_ci  imap_cancel_authenticate,   /* Send authentication cancellation */
18313498266Sopenharmony_ci  imap_get_message,           /* Get SASL response message */
18413498266Sopenharmony_ci  0,                          /* No maximum initial response length */
18513498266Sopenharmony_ci  '+',                        /* Code received when continuation is expected */
18613498266Sopenharmony_ci  IMAP_RESP_OK,               /* Code to receive upon authentication success */
18713498266Sopenharmony_ci  SASL_AUTH_DEFAULT,          /* Default mechanisms */
18813498266Sopenharmony_ci  SASL_FLAG_BASE64            /* Configuration flags */
18913498266Sopenharmony_ci};
19013498266Sopenharmony_ci
19113498266Sopenharmony_ci
19213498266Sopenharmony_ci#ifdef USE_SSL
19313498266Sopenharmony_cistatic void imap_to_imaps(struct connectdata *conn)
19413498266Sopenharmony_ci{
19513498266Sopenharmony_ci  /* Change the connection handler */
19613498266Sopenharmony_ci  conn->handler = &Curl_handler_imaps;
19713498266Sopenharmony_ci
19813498266Sopenharmony_ci  /* Set the connection's upgraded to TLS flag */
19913498266Sopenharmony_ci  conn->bits.tls_upgraded = TRUE;
20013498266Sopenharmony_ci}
20113498266Sopenharmony_ci#else
20213498266Sopenharmony_ci#define imap_to_imaps(x) Curl_nop_stmt
20313498266Sopenharmony_ci#endif
20413498266Sopenharmony_ci
20513498266Sopenharmony_ci/***********************************************************************
20613498266Sopenharmony_ci *
20713498266Sopenharmony_ci * imap_matchresp()
20813498266Sopenharmony_ci *
20913498266Sopenharmony_ci * Determines whether the untagged response is related to the specified
21013498266Sopenharmony_ci * command by checking if it is in format "* <command-name> ..." or
21113498266Sopenharmony_ci * "* <number> <command-name> ...".
21213498266Sopenharmony_ci *
21313498266Sopenharmony_ci * The "* " marker is assumed to have already been checked by the caller.
21413498266Sopenharmony_ci */
21513498266Sopenharmony_cistatic bool imap_matchresp(const char *line, size_t len, const char *cmd)
21613498266Sopenharmony_ci{
21713498266Sopenharmony_ci  const char *end = line + len;
21813498266Sopenharmony_ci  size_t cmd_len = strlen(cmd);
21913498266Sopenharmony_ci
22013498266Sopenharmony_ci  /* Skip the untagged response marker */
22113498266Sopenharmony_ci  line += 2;
22213498266Sopenharmony_ci
22313498266Sopenharmony_ci  /* Do we have a number after the marker? */
22413498266Sopenharmony_ci  if(line < end && ISDIGIT(*line)) {
22513498266Sopenharmony_ci    /* Skip the number */
22613498266Sopenharmony_ci    do
22713498266Sopenharmony_ci      line++;
22813498266Sopenharmony_ci    while(line < end && ISDIGIT(*line));
22913498266Sopenharmony_ci
23013498266Sopenharmony_ci    /* Do we have the space character? */
23113498266Sopenharmony_ci    if(line == end || *line != ' ')
23213498266Sopenharmony_ci      return FALSE;
23313498266Sopenharmony_ci
23413498266Sopenharmony_ci    line++;
23513498266Sopenharmony_ci  }
23613498266Sopenharmony_ci
23713498266Sopenharmony_ci  /* Does the command name match and is it followed by a space character or at
23813498266Sopenharmony_ci     the end of line? */
23913498266Sopenharmony_ci  if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) &&
24013498266Sopenharmony_ci     (line[cmd_len] == ' ' || line + cmd_len + 2 == end))
24113498266Sopenharmony_ci    return TRUE;
24213498266Sopenharmony_ci
24313498266Sopenharmony_ci  return FALSE;
24413498266Sopenharmony_ci}
24513498266Sopenharmony_ci
24613498266Sopenharmony_ci/***********************************************************************
24713498266Sopenharmony_ci *
24813498266Sopenharmony_ci * imap_endofresp()
24913498266Sopenharmony_ci *
25013498266Sopenharmony_ci * Checks whether the given string is a valid tagged, untagged or continuation
25113498266Sopenharmony_ci * response which can be processed by the response handler.
25213498266Sopenharmony_ci */
25313498266Sopenharmony_cistatic bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
25413498266Sopenharmony_ci                           char *line, size_t len, int *resp)
25513498266Sopenharmony_ci{
25613498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
25713498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
25813498266Sopenharmony_ci  const char *id = imapc->resptag;
25913498266Sopenharmony_ci  size_t id_len = strlen(id);
26013498266Sopenharmony_ci
26113498266Sopenharmony_ci  /* Do we have a tagged command response? */
26213498266Sopenharmony_ci  if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') {
26313498266Sopenharmony_ci    line += id_len + 1;
26413498266Sopenharmony_ci    len -= id_len + 1;
26513498266Sopenharmony_ci
26613498266Sopenharmony_ci    if(len >= 2 && !memcmp(line, "OK", 2))
26713498266Sopenharmony_ci      *resp = IMAP_RESP_OK;
26813498266Sopenharmony_ci    else if(len >= 7 && !memcmp(line, "PREAUTH", 7))
26913498266Sopenharmony_ci      *resp = IMAP_RESP_PREAUTH;
27013498266Sopenharmony_ci    else
27113498266Sopenharmony_ci      *resp = IMAP_RESP_NOT_OK;
27213498266Sopenharmony_ci
27313498266Sopenharmony_ci    return TRUE;
27413498266Sopenharmony_ci  }
27513498266Sopenharmony_ci
27613498266Sopenharmony_ci  /* Do we have an untagged command response? */
27713498266Sopenharmony_ci  if(len >= 2 && !memcmp("* ", line, 2)) {
27813498266Sopenharmony_ci    switch(imapc->state) {
27913498266Sopenharmony_ci      /* States which are interested in untagged responses */
28013498266Sopenharmony_ci      case IMAP_CAPABILITY:
28113498266Sopenharmony_ci        if(!imap_matchresp(line, len, "CAPABILITY"))
28213498266Sopenharmony_ci          return FALSE;
28313498266Sopenharmony_ci        break;
28413498266Sopenharmony_ci
28513498266Sopenharmony_ci      case IMAP_LIST:
28613498266Sopenharmony_ci        if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
28713498266Sopenharmony_ci          (imap->custom && !imap_matchresp(line, len, imap->custom) &&
28813498266Sopenharmony_ci           (!strcasecompare(imap->custom, "STORE") ||
28913498266Sopenharmony_ci            !imap_matchresp(line, len, "FETCH")) &&
29013498266Sopenharmony_ci           !strcasecompare(imap->custom, "SELECT") &&
29113498266Sopenharmony_ci           !strcasecompare(imap->custom, "EXAMINE") &&
29213498266Sopenharmony_ci           !strcasecompare(imap->custom, "SEARCH") &&
29313498266Sopenharmony_ci           !strcasecompare(imap->custom, "EXPUNGE") &&
29413498266Sopenharmony_ci           !strcasecompare(imap->custom, "LSUB") &&
29513498266Sopenharmony_ci           !strcasecompare(imap->custom, "UID") &&
29613498266Sopenharmony_ci           !strcasecompare(imap->custom, "GETQUOTAROOT") &&
29713498266Sopenharmony_ci           !strcasecompare(imap->custom, "NOOP")))
29813498266Sopenharmony_ci          return FALSE;
29913498266Sopenharmony_ci        break;
30013498266Sopenharmony_ci
30113498266Sopenharmony_ci      case IMAP_SELECT:
30213498266Sopenharmony_ci        /* SELECT is special in that its untagged responses do not have a
30313498266Sopenharmony_ci           common prefix so accept anything! */
30413498266Sopenharmony_ci        break;
30513498266Sopenharmony_ci
30613498266Sopenharmony_ci      case IMAP_FETCH:
30713498266Sopenharmony_ci        if(!imap_matchresp(line, len, "FETCH"))
30813498266Sopenharmony_ci          return FALSE;
30913498266Sopenharmony_ci        break;
31013498266Sopenharmony_ci
31113498266Sopenharmony_ci      case IMAP_SEARCH:
31213498266Sopenharmony_ci        if(!imap_matchresp(line, len, "SEARCH"))
31313498266Sopenharmony_ci          return FALSE;
31413498266Sopenharmony_ci        break;
31513498266Sopenharmony_ci
31613498266Sopenharmony_ci      /* Ignore other untagged responses */
31713498266Sopenharmony_ci      default:
31813498266Sopenharmony_ci        return FALSE;
31913498266Sopenharmony_ci    }
32013498266Sopenharmony_ci
32113498266Sopenharmony_ci    *resp = '*';
32213498266Sopenharmony_ci    return TRUE;
32313498266Sopenharmony_ci  }
32413498266Sopenharmony_ci
32513498266Sopenharmony_ci  /* Do we have a continuation response? This should be a + symbol followed by
32613498266Sopenharmony_ci     a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
32713498266Sopenharmony_ci     APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
32813498266Sopenharmony_ci     some email servers ignore this and only send a single + instead. */
32913498266Sopenharmony_ci  if(imap && !imap->custom && ((len == 3 && line[0] == '+') ||
33013498266Sopenharmony_ci     (len >= 2 && !memcmp("+ ", line, 2)))) {
33113498266Sopenharmony_ci    switch(imapc->state) {
33213498266Sopenharmony_ci      /* States which are interested in continuation responses */
33313498266Sopenharmony_ci      case IMAP_AUTHENTICATE:
33413498266Sopenharmony_ci      case IMAP_APPEND:
33513498266Sopenharmony_ci        *resp = '+';
33613498266Sopenharmony_ci        break;
33713498266Sopenharmony_ci
33813498266Sopenharmony_ci      default:
33913498266Sopenharmony_ci        failf(data, "Unexpected continuation response");
34013498266Sopenharmony_ci        *resp = -1;
34113498266Sopenharmony_ci        break;
34213498266Sopenharmony_ci    }
34313498266Sopenharmony_ci
34413498266Sopenharmony_ci    return TRUE;
34513498266Sopenharmony_ci  }
34613498266Sopenharmony_ci
34713498266Sopenharmony_ci  return FALSE; /* Nothing for us */
34813498266Sopenharmony_ci}
34913498266Sopenharmony_ci
35013498266Sopenharmony_ci/***********************************************************************
35113498266Sopenharmony_ci *
35213498266Sopenharmony_ci * imap_get_message()
35313498266Sopenharmony_ci *
35413498266Sopenharmony_ci * Gets the authentication message from the response buffer.
35513498266Sopenharmony_ci */
35613498266Sopenharmony_cistatic CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out)
35713498266Sopenharmony_ci{
35813498266Sopenharmony_ci  char *message = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
35913498266Sopenharmony_ci  size_t len = data->conn->proto.imapc.pp.nfinal;
36013498266Sopenharmony_ci
36113498266Sopenharmony_ci  if(len > 2) {
36213498266Sopenharmony_ci    /* Find the start of the message */
36313498266Sopenharmony_ci    len -= 2;
36413498266Sopenharmony_ci    for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
36513498266Sopenharmony_ci      ;
36613498266Sopenharmony_ci
36713498266Sopenharmony_ci    /* Find the end of the message */
36813498266Sopenharmony_ci    while(len--)
36913498266Sopenharmony_ci      if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
37013498266Sopenharmony_ci         message[len] != '\t')
37113498266Sopenharmony_ci        break;
37213498266Sopenharmony_ci
37313498266Sopenharmony_ci    /* Terminate the message */
37413498266Sopenharmony_ci    message[++len] = '\0';
37513498266Sopenharmony_ci    Curl_bufref_set(out, message, len, NULL);
37613498266Sopenharmony_ci  }
37713498266Sopenharmony_ci  else
37813498266Sopenharmony_ci    /* junk input => zero length output */
37913498266Sopenharmony_ci    Curl_bufref_set(out, "", 0, NULL);
38013498266Sopenharmony_ci
38113498266Sopenharmony_ci  return CURLE_OK;
38213498266Sopenharmony_ci}
38313498266Sopenharmony_ci
38413498266Sopenharmony_ci/***********************************************************************
38513498266Sopenharmony_ci *
38613498266Sopenharmony_ci * imap_state()
38713498266Sopenharmony_ci *
38813498266Sopenharmony_ci * This is the ONLY way to change IMAP state!
38913498266Sopenharmony_ci */
39013498266Sopenharmony_cistatic void imap_state(struct Curl_easy *data, imapstate newstate)
39113498266Sopenharmony_ci{
39213498266Sopenharmony_ci  struct imap_conn *imapc = &data->conn->proto.imapc;
39313498266Sopenharmony_ci#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
39413498266Sopenharmony_ci  /* for debug purposes */
39513498266Sopenharmony_ci  static const char * const names[]={
39613498266Sopenharmony_ci    "STOP",
39713498266Sopenharmony_ci    "SERVERGREET",
39813498266Sopenharmony_ci    "CAPABILITY",
39913498266Sopenharmony_ci    "STARTTLS",
40013498266Sopenharmony_ci    "UPGRADETLS",
40113498266Sopenharmony_ci    "AUTHENTICATE",
40213498266Sopenharmony_ci    "LOGIN",
40313498266Sopenharmony_ci    "LIST",
40413498266Sopenharmony_ci    "SELECT",
40513498266Sopenharmony_ci    "FETCH",
40613498266Sopenharmony_ci    "FETCH_FINAL",
40713498266Sopenharmony_ci    "APPEND",
40813498266Sopenharmony_ci    "APPEND_FINAL",
40913498266Sopenharmony_ci    "SEARCH",
41013498266Sopenharmony_ci    "LOGOUT",
41113498266Sopenharmony_ci    /* LAST */
41213498266Sopenharmony_ci  };
41313498266Sopenharmony_ci
41413498266Sopenharmony_ci  if(imapc->state != newstate)
41513498266Sopenharmony_ci    infof(data, "IMAP %p state change from %s to %s",
41613498266Sopenharmony_ci          (void *)imapc, names[imapc->state], names[newstate]);
41713498266Sopenharmony_ci#endif
41813498266Sopenharmony_ci
41913498266Sopenharmony_ci  imapc->state = newstate;
42013498266Sopenharmony_ci}
42113498266Sopenharmony_ci
42213498266Sopenharmony_ci/***********************************************************************
42313498266Sopenharmony_ci *
42413498266Sopenharmony_ci * imap_perform_capability()
42513498266Sopenharmony_ci *
42613498266Sopenharmony_ci * Sends the CAPABILITY command in order to obtain a list of server side
42713498266Sopenharmony_ci * supported capabilities.
42813498266Sopenharmony_ci */
42913498266Sopenharmony_cistatic CURLcode imap_perform_capability(struct Curl_easy *data,
43013498266Sopenharmony_ci                                        struct connectdata *conn)
43113498266Sopenharmony_ci{
43213498266Sopenharmony_ci  CURLcode result = CURLE_OK;
43313498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
43413498266Sopenharmony_ci  imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
43513498266Sopenharmony_ci  imapc->sasl.authused = SASL_AUTH_NONE;  /* Clear the auth. mechanism used */
43613498266Sopenharmony_ci  imapc->tls_supported = FALSE;           /* Clear the TLS capability */
43713498266Sopenharmony_ci
43813498266Sopenharmony_ci  /* Send the CAPABILITY command */
43913498266Sopenharmony_ci  result = imap_sendf(data, "CAPABILITY");
44013498266Sopenharmony_ci
44113498266Sopenharmony_ci  if(!result)
44213498266Sopenharmony_ci    imap_state(data, IMAP_CAPABILITY);
44313498266Sopenharmony_ci
44413498266Sopenharmony_ci  return result;
44513498266Sopenharmony_ci}
44613498266Sopenharmony_ci
44713498266Sopenharmony_ci/***********************************************************************
44813498266Sopenharmony_ci *
44913498266Sopenharmony_ci * imap_perform_starttls()
45013498266Sopenharmony_ci *
45113498266Sopenharmony_ci * Sends the STARTTLS command to start the upgrade to TLS.
45213498266Sopenharmony_ci */
45313498266Sopenharmony_cistatic CURLcode imap_perform_starttls(struct Curl_easy *data)
45413498266Sopenharmony_ci{
45513498266Sopenharmony_ci  /* Send the STARTTLS command */
45613498266Sopenharmony_ci  CURLcode result = imap_sendf(data, "STARTTLS");
45713498266Sopenharmony_ci
45813498266Sopenharmony_ci  if(!result)
45913498266Sopenharmony_ci    imap_state(data, IMAP_STARTTLS);
46013498266Sopenharmony_ci
46113498266Sopenharmony_ci  return result;
46213498266Sopenharmony_ci}
46313498266Sopenharmony_ci
46413498266Sopenharmony_ci/***********************************************************************
46513498266Sopenharmony_ci *
46613498266Sopenharmony_ci * imap_perform_upgrade_tls()
46713498266Sopenharmony_ci *
46813498266Sopenharmony_ci * Performs the upgrade to TLS.
46913498266Sopenharmony_ci */
47013498266Sopenharmony_cistatic CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
47113498266Sopenharmony_ci                                         struct connectdata *conn)
47213498266Sopenharmony_ci{
47313498266Sopenharmony_ci  /* Start the SSL connection */
47413498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
47513498266Sopenharmony_ci  CURLcode result;
47613498266Sopenharmony_ci  bool ssldone = FALSE;
47713498266Sopenharmony_ci
47813498266Sopenharmony_ci  if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
47913498266Sopenharmony_ci    result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
48013498266Sopenharmony_ci    if(result)
48113498266Sopenharmony_ci      goto out;
48213498266Sopenharmony_ci  }
48313498266Sopenharmony_ci
48413498266Sopenharmony_ci  result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
48513498266Sopenharmony_ci  if(!result) {
48613498266Sopenharmony_ci    imapc->ssldone = ssldone;
48713498266Sopenharmony_ci    if(imapc->state != IMAP_UPGRADETLS)
48813498266Sopenharmony_ci      imap_state(data, IMAP_UPGRADETLS);
48913498266Sopenharmony_ci
49013498266Sopenharmony_ci    if(imapc->ssldone) {
49113498266Sopenharmony_ci      imap_to_imaps(conn);
49213498266Sopenharmony_ci      result = imap_perform_capability(data, conn);
49313498266Sopenharmony_ci    }
49413498266Sopenharmony_ci  }
49513498266Sopenharmony_ciout:
49613498266Sopenharmony_ci  return result;
49713498266Sopenharmony_ci}
49813498266Sopenharmony_ci
49913498266Sopenharmony_ci/***********************************************************************
50013498266Sopenharmony_ci *
50113498266Sopenharmony_ci * imap_perform_login()
50213498266Sopenharmony_ci *
50313498266Sopenharmony_ci * Sends a clear text LOGIN command to authenticate with.
50413498266Sopenharmony_ci */
50513498266Sopenharmony_cistatic CURLcode imap_perform_login(struct Curl_easy *data,
50613498266Sopenharmony_ci                                   struct connectdata *conn)
50713498266Sopenharmony_ci{
50813498266Sopenharmony_ci  CURLcode result = CURLE_OK;
50913498266Sopenharmony_ci  char *user;
51013498266Sopenharmony_ci  char *passwd;
51113498266Sopenharmony_ci
51213498266Sopenharmony_ci  /* Check we have a username and password to authenticate with and end the
51313498266Sopenharmony_ci     connect phase if we don't */
51413498266Sopenharmony_ci  if(!data->state.aptr.user) {
51513498266Sopenharmony_ci    imap_state(data, IMAP_STOP);
51613498266Sopenharmony_ci
51713498266Sopenharmony_ci    return result;
51813498266Sopenharmony_ci  }
51913498266Sopenharmony_ci
52013498266Sopenharmony_ci  /* Make sure the username and password are in the correct atom format */
52113498266Sopenharmony_ci  user = imap_atom(conn->user, false);
52213498266Sopenharmony_ci  passwd = imap_atom(conn->passwd, false);
52313498266Sopenharmony_ci
52413498266Sopenharmony_ci  /* Send the LOGIN command */
52513498266Sopenharmony_ci  result = imap_sendf(data, "LOGIN %s %s", user ? user : "",
52613498266Sopenharmony_ci                      passwd ? passwd : "");
52713498266Sopenharmony_ci
52813498266Sopenharmony_ci  free(user);
52913498266Sopenharmony_ci  free(passwd);
53013498266Sopenharmony_ci
53113498266Sopenharmony_ci  if(!result)
53213498266Sopenharmony_ci    imap_state(data, IMAP_LOGIN);
53313498266Sopenharmony_ci
53413498266Sopenharmony_ci  return result;
53513498266Sopenharmony_ci}
53613498266Sopenharmony_ci
53713498266Sopenharmony_ci/***********************************************************************
53813498266Sopenharmony_ci *
53913498266Sopenharmony_ci * imap_perform_authenticate()
54013498266Sopenharmony_ci *
54113498266Sopenharmony_ci * Sends an AUTHENTICATE command allowing the client to login with the given
54213498266Sopenharmony_ci * SASL authentication mechanism.
54313498266Sopenharmony_ci */
54413498266Sopenharmony_cistatic CURLcode imap_perform_authenticate(struct Curl_easy *data,
54513498266Sopenharmony_ci                                          const char *mech,
54613498266Sopenharmony_ci                                          const struct bufref *initresp)
54713498266Sopenharmony_ci{
54813498266Sopenharmony_ci  CURLcode result = CURLE_OK;
54913498266Sopenharmony_ci  const char *ir = (const char *) Curl_bufref_ptr(initresp);
55013498266Sopenharmony_ci
55113498266Sopenharmony_ci  if(ir) {
55213498266Sopenharmony_ci    /* Send the AUTHENTICATE command with the initial response */
55313498266Sopenharmony_ci    result = imap_sendf(data, "AUTHENTICATE %s %s", mech, ir);
55413498266Sopenharmony_ci  }
55513498266Sopenharmony_ci  else {
55613498266Sopenharmony_ci    /* Send the AUTHENTICATE command */
55713498266Sopenharmony_ci    result = imap_sendf(data, "AUTHENTICATE %s", mech);
55813498266Sopenharmony_ci  }
55913498266Sopenharmony_ci
56013498266Sopenharmony_ci  return result;
56113498266Sopenharmony_ci}
56213498266Sopenharmony_ci
56313498266Sopenharmony_ci/***********************************************************************
56413498266Sopenharmony_ci *
56513498266Sopenharmony_ci * imap_continue_authenticate()
56613498266Sopenharmony_ci *
56713498266Sopenharmony_ci * Sends SASL continuation data.
56813498266Sopenharmony_ci */
56913498266Sopenharmony_cistatic CURLcode imap_continue_authenticate(struct Curl_easy *data,
57013498266Sopenharmony_ci                                           const char *mech,
57113498266Sopenharmony_ci                                           const struct bufref *resp)
57213498266Sopenharmony_ci{
57313498266Sopenharmony_ci  struct imap_conn *imapc = &data->conn->proto.imapc;
57413498266Sopenharmony_ci
57513498266Sopenharmony_ci  (void)mech;
57613498266Sopenharmony_ci
57713498266Sopenharmony_ci  return Curl_pp_sendf(data, &imapc->pp,
57813498266Sopenharmony_ci                       "%s", (const char *) Curl_bufref_ptr(resp));
57913498266Sopenharmony_ci}
58013498266Sopenharmony_ci
58113498266Sopenharmony_ci/***********************************************************************
58213498266Sopenharmony_ci *
58313498266Sopenharmony_ci * imap_cancel_authenticate()
58413498266Sopenharmony_ci *
58513498266Sopenharmony_ci * Sends SASL cancellation.
58613498266Sopenharmony_ci */
58713498266Sopenharmony_cistatic CURLcode imap_cancel_authenticate(struct Curl_easy *data,
58813498266Sopenharmony_ci                                         const char *mech)
58913498266Sopenharmony_ci{
59013498266Sopenharmony_ci  struct imap_conn *imapc = &data->conn->proto.imapc;
59113498266Sopenharmony_ci
59213498266Sopenharmony_ci  (void)mech;
59313498266Sopenharmony_ci
59413498266Sopenharmony_ci  return Curl_pp_sendf(data, &imapc->pp, "*");
59513498266Sopenharmony_ci}
59613498266Sopenharmony_ci
59713498266Sopenharmony_ci/***********************************************************************
59813498266Sopenharmony_ci *
59913498266Sopenharmony_ci * imap_perform_authentication()
60013498266Sopenharmony_ci *
60113498266Sopenharmony_ci * Initiates the authentication sequence, with the appropriate SASL
60213498266Sopenharmony_ci * authentication mechanism, falling back to clear text should a common
60313498266Sopenharmony_ci * mechanism not be available between the client and server.
60413498266Sopenharmony_ci */
60513498266Sopenharmony_cistatic CURLcode imap_perform_authentication(struct Curl_easy *data,
60613498266Sopenharmony_ci                                            struct connectdata *conn)
60713498266Sopenharmony_ci{
60813498266Sopenharmony_ci  CURLcode result = CURLE_OK;
60913498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
61013498266Sopenharmony_ci  saslprogress progress;
61113498266Sopenharmony_ci
61213498266Sopenharmony_ci  /* Check if already authenticated OR if there is enough data to authenticate
61313498266Sopenharmony_ci     with and end the connect phase if we don't */
61413498266Sopenharmony_ci  if(imapc->preauth ||
61513498266Sopenharmony_ci     !Curl_sasl_can_authenticate(&imapc->sasl, data)) {
61613498266Sopenharmony_ci    imap_state(data, IMAP_STOP);
61713498266Sopenharmony_ci    return result;
61813498266Sopenharmony_ci  }
61913498266Sopenharmony_ci
62013498266Sopenharmony_ci  /* Calculate the SASL login details */
62113498266Sopenharmony_ci  result = Curl_sasl_start(&imapc->sasl, data, imapc->ir_supported, &progress);
62213498266Sopenharmony_ci
62313498266Sopenharmony_ci  if(!result) {
62413498266Sopenharmony_ci    if(progress == SASL_INPROGRESS)
62513498266Sopenharmony_ci      imap_state(data, IMAP_AUTHENTICATE);
62613498266Sopenharmony_ci    else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
62713498266Sopenharmony_ci      /* Perform clear text authentication */
62813498266Sopenharmony_ci      result = imap_perform_login(data, conn);
62913498266Sopenharmony_ci    else {
63013498266Sopenharmony_ci      /* Other mechanisms not supported */
63113498266Sopenharmony_ci      infof(data, "No known authentication mechanisms supported");
63213498266Sopenharmony_ci      result = CURLE_LOGIN_DENIED;
63313498266Sopenharmony_ci    }
63413498266Sopenharmony_ci  }
63513498266Sopenharmony_ci
63613498266Sopenharmony_ci  return result;
63713498266Sopenharmony_ci}
63813498266Sopenharmony_ci
63913498266Sopenharmony_ci/***********************************************************************
64013498266Sopenharmony_ci *
64113498266Sopenharmony_ci * imap_perform_list()
64213498266Sopenharmony_ci *
64313498266Sopenharmony_ci * Sends a LIST command or an alternative custom request.
64413498266Sopenharmony_ci */
64513498266Sopenharmony_cistatic CURLcode imap_perform_list(struct Curl_easy *data)
64613498266Sopenharmony_ci{
64713498266Sopenharmony_ci  CURLcode result = CURLE_OK;
64813498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
64913498266Sopenharmony_ci
65013498266Sopenharmony_ci  if(imap->custom)
65113498266Sopenharmony_ci    /* Send the custom request */
65213498266Sopenharmony_ci    result = imap_sendf(data, "%s%s", imap->custom,
65313498266Sopenharmony_ci                        imap->custom_params ? imap->custom_params : "");
65413498266Sopenharmony_ci  else {
65513498266Sopenharmony_ci    /* Make sure the mailbox is in the correct atom format if necessary */
65613498266Sopenharmony_ci    char *mailbox = imap->mailbox ? imap_atom(imap->mailbox, true)
65713498266Sopenharmony_ci                                  : strdup("");
65813498266Sopenharmony_ci    if(!mailbox)
65913498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
66013498266Sopenharmony_ci
66113498266Sopenharmony_ci    /* Send the LIST command */
66213498266Sopenharmony_ci    result = imap_sendf(data, "LIST \"%s\" *", mailbox);
66313498266Sopenharmony_ci
66413498266Sopenharmony_ci    free(mailbox);
66513498266Sopenharmony_ci  }
66613498266Sopenharmony_ci
66713498266Sopenharmony_ci  if(!result)
66813498266Sopenharmony_ci    imap_state(data, IMAP_LIST);
66913498266Sopenharmony_ci
67013498266Sopenharmony_ci  return result;
67113498266Sopenharmony_ci}
67213498266Sopenharmony_ci
67313498266Sopenharmony_ci/***********************************************************************
67413498266Sopenharmony_ci *
67513498266Sopenharmony_ci * imap_perform_select()
67613498266Sopenharmony_ci *
67713498266Sopenharmony_ci * Sends a SELECT command to ask the server to change the selected mailbox.
67813498266Sopenharmony_ci */
67913498266Sopenharmony_cistatic CURLcode imap_perform_select(struct Curl_easy *data)
68013498266Sopenharmony_ci{
68113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
68213498266Sopenharmony_ci  struct connectdata *conn = data->conn;
68313498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
68413498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
68513498266Sopenharmony_ci  char *mailbox;
68613498266Sopenharmony_ci
68713498266Sopenharmony_ci  /* Invalidate old information as we are switching mailboxes */
68813498266Sopenharmony_ci  Curl_safefree(imapc->mailbox);
68913498266Sopenharmony_ci  Curl_safefree(imapc->mailbox_uidvalidity);
69013498266Sopenharmony_ci
69113498266Sopenharmony_ci  /* Check we have a mailbox */
69213498266Sopenharmony_ci  if(!imap->mailbox) {
69313498266Sopenharmony_ci    failf(data, "Cannot SELECT without a mailbox.");
69413498266Sopenharmony_ci    return CURLE_URL_MALFORMAT;
69513498266Sopenharmony_ci  }
69613498266Sopenharmony_ci
69713498266Sopenharmony_ci  /* Make sure the mailbox is in the correct atom format */
69813498266Sopenharmony_ci  mailbox = imap_atom(imap->mailbox, false);
69913498266Sopenharmony_ci  if(!mailbox)
70013498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
70113498266Sopenharmony_ci
70213498266Sopenharmony_ci  /* Send the SELECT command */
70313498266Sopenharmony_ci  result = imap_sendf(data, "SELECT %s", mailbox);
70413498266Sopenharmony_ci
70513498266Sopenharmony_ci  free(mailbox);
70613498266Sopenharmony_ci
70713498266Sopenharmony_ci  if(!result)
70813498266Sopenharmony_ci    imap_state(data, IMAP_SELECT);
70913498266Sopenharmony_ci
71013498266Sopenharmony_ci  return result;
71113498266Sopenharmony_ci}
71213498266Sopenharmony_ci
71313498266Sopenharmony_ci/***********************************************************************
71413498266Sopenharmony_ci *
71513498266Sopenharmony_ci * imap_perform_fetch()
71613498266Sopenharmony_ci *
71713498266Sopenharmony_ci * Sends a FETCH command to initiate the download of a message.
71813498266Sopenharmony_ci */
71913498266Sopenharmony_cistatic CURLcode imap_perform_fetch(struct Curl_easy *data)
72013498266Sopenharmony_ci{
72113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
72213498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
72313498266Sopenharmony_ci  /* Check we have a UID */
72413498266Sopenharmony_ci  if(imap->uid) {
72513498266Sopenharmony_ci
72613498266Sopenharmony_ci    /* Send the FETCH command */
72713498266Sopenharmony_ci    if(imap->partial)
72813498266Sopenharmony_ci      result = imap_sendf(data, "UID FETCH %s BODY[%s]<%s>",
72913498266Sopenharmony_ci                          imap->uid, imap->section ? imap->section : "",
73013498266Sopenharmony_ci                          imap->partial);
73113498266Sopenharmony_ci    else
73213498266Sopenharmony_ci      result = imap_sendf(data, "UID FETCH %s BODY[%s]",
73313498266Sopenharmony_ci                          imap->uid, imap->section ? imap->section : "");
73413498266Sopenharmony_ci  }
73513498266Sopenharmony_ci  else if(imap->mindex) {
73613498266Sopenharmony_ci    /* Send the FETCH command */
73713498266Sopenharmony_ci    if(imap->partial)
73813498266Sopenharmony_ci      result = imap_sendf(data, "FETCH %s BODY[%s]<%s>",
73913498266Sopenharmony_ci                          imap->mindex, imap->section ? imap->section : "",
74013498266Sopenharmony_ci                          imap->partial);
74113498266Sopenharmony_ci    else
74213498266Sopenharmony_ci      result = imap_sendf(data, "FETCH %s BODY[%s]",
74313498266Sopenharmony_ci                          imap->mindex, imap->section ? imap->section : "");
74413498266Sopenharmony_ci  }
74513498266Sopenharmony_ci  else {
74613498266Sopenharmony_ci    failf(data, "Cannot FETCH without a UID.");
74713498266Sopenharmony_ci    return CURLE_URL_MALFORMAT;
74813498266Sopenharmony_ci  }
74913498266Sopenharmony_ci  if(!result)
75013498266Sopenharmony_ci    imap_state(data, IMAP_FETCH);
75113498266Sopenharmony_ci
75213498266Sopenharmony_ci  return result;
75313498266Sopenharmony_ci}
75413498266Sopenharmony_ci
75513498266Sopenharmony_ci/***********************************************************************
75613498266Sopenharmony_ci *
75713498266Sopenharmony_ci * imap_perform_append()
75813498266Sopenharmony_ci *
75913498266Sopenharmony_ci * Sends an APPEND command to initiate the upload of a message.
76013498266Sopenharmony_ci */
76113498266Sopenharmony_cistatic CURLcode imap_perform_append(struct Curl_easy *data)
76213498266Sopenharmony_ci{
76313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
76413498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
76513498266Sopenharmony_ci  char *mailbox;
76613498266Sopenharmony_ci
76713498266Sopenharmony_ci  /* Check we have a mailbox */
76813498266Sopenharmony_ci  if(!imap->mailbox) {
76913498266Sopenharmony_ci    failf(data, "Cannot APPEND without a mailbox.");
77013498266Sopenharmony_ci    return CURLE_URL_MALFORMAT;
77113498266Sopenharmony_ci  }
77213498266Sopenharmony_ci
77313498266Sopenharmony_ci  /* Prepare the mime data if some. */
77413498266Sopenharmony_ci  if(data->set.mimepost.kind != MIMEKIND_NONE) {
77513498266Sopenharmony_ci    /* Use the whole structure as data. */
77613498266Sopenharmony_ci    data->set.mimepost.flags &= ~MIME_BODY_ONLY;
77713498266Sopenharmony_ci
77813498266Sopenharmony_ci    /* Add external headers and mime version. */
77913498266Sopenharmony_ci    curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
78013498266Sopenharmony_ci    result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
78113498266Sopenharmony_ci                                       NULL, MIMESTRATEGY_MAIL);
78213498266Sopenharmony_ci
78313498266Sopenharmony_ci    if(!result)
78413498266Sopenharmony_ci      if(!Curl_checkheaders(data, STRCONST("Mime-Version")))
78513498266Sopenharmony_ci        result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
78613498266Sopenharmony_ci                                      "Mime-Version: 1.0");
78713498266Sopenharmony_ci
78813498266Sopenharmony_ci    /* Make sure we will read the entire mime structure. */
78913498266Sopenharmony_ci    if(!result)
79013498266Sopenharmony_ci      result = Curl_mime_rewind(&data->set.mimepost);
79113498266Sopenharmony_ci
79213498266Sopenharmony_ci    if(result)
79313498266Sopenharmony_ci      return result;
79413498266Sopenharmony_ci
79513498266Sopenharmony_ci    data->state.infilesize = Curl_mime_size(&data->set.mimepost);
79613498266Sopenharmony_ci
79713498266Sopenharmony_ci    /* Read from mime structure. */
79813498266Sopenharmony_ci    data->state.fread_func = (curl_read_callback) Curl_mime_read;
79913498266Sopenharmony_ci    data->state.in = (void *) &data->set.mimepost;
80013498266Sopenharmony_ci  }
80113498266Sopenharmony_ci
80213498266Sopenharmony_ci  /* Check we know the size of the upload */
80313498266Sopenharmony_ci  if(data->state.infilesize < 0) {
80413498266Sopenharmony_ci    failf(data, "Cannot APPEND with unknown input file size");
80513498266Sopenharmony_ci    return CURLE_UPLOAD_FAILED;
80613498266Sopenharmony_ci  }
80713498266Sopenharmony_ci
80813498266Sopenharmony_ci  /* Make sure the mailbox is in the correct atom format */
80913498266Sopenharmony_ci  mailbox = imap_atom(imap->mailbox, false);
81013498266Sopenharmony_ci  if(!mailbox)
81113498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
81213498266Sopenharmony_ci
81313498266Sopenharmony_ci  /* Send the APPEND command */
81413498266Sopenharmony_ci  result = imap_sendf(data,
81513498266Sopenharmony_ci                      "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
81613498266Sopenharmony_ci                      mailbox, data->state.infilesize);
81713498266Sopenharmony_ci
81813498266Sopenharmony_ci  free(mailbox);
81913498266Sopenharmony_ci
82013498266Sopenharmony_ci  if(!result)
82113498266Sopenharmony_ci    imap_state(data, IMAP_APPEND);
82213498266Sopenharmony_ci
82313498266Sopenharmony_ci  return result;
82413498266Sopenharmony_ci}
82513498266Sopenharmony_ci
82613498266Sopenharmony_ci/***********************************************************************
82713498266Sopenharmony_ci *
82813498266Sopenharmony_ci * imap_perform_search()
82913498266Sopenharmony_ci *
83013498266Sopenharmony_ci * Sends a SEARCH command.
83113498266Sopenharmony_ci */
83213498266Sopenharmony_cistatic CURLcode imap_perform_search(struct Curl_easy *data)
83313498266Sopenharmony_ci{
83413498266Sopenharmony_ci  CURLcode result = CURLE_OK;
83513498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
83613498266Sopenharmony_ci
83713498266Sopenharmony_ci  /* Check we have a query string */
83813498266Sopenharmony_ci  if(!imap->query) {
83913498266Sopenharmony_ci    failf(data, "Cannot SEARCH without a query string.");
84013498266Sopenharmony_ci    return CURLE_URL_MALFORMAT;
84113498266Sopenharmony_ci  }
84213498266Sopenharmony_ci
84313498266Sopenharmony_ci  /* Send the SEARCH command */
84413498266Sopenharmony_ci  result = imap_sendf(data, "SEARCH %s", imap->query);
84513498266Sopenharmony_ci
84613498266Sopenharmony_ci  if(!result)
84713498266Sopenharmony_ci    imap_state(data, IMAP_SEARCH);
84813498266Sopenharmony_ci
84913498266Sopenharmony_ci  return result;
85013498266Sopenharmony_ci}
85113498266Sopenharmony_ci
85213498266Sopenharmony_ci/***********************************************************************
85313498266Sopenharmony_ci *
85413498266Sopenharmony_ci * imap_perform_logout()
85513498266Sopenharmony_ci *
85613498266Sopenharmony_ci * Performs the logout action prior to sclose() being called.
85713498266Sopenharmony_ci */
85813498266Sopenharmony_cistatic CURLcode imap_perform_logout(struct Curl_easy *data)
85913498266Sopenharmony_ci{
86013498266Sopenharmony_ci  /* Send the LOGOUT command */
86113498266Sopenharmony_ci  CURLcode result = imap_sendf(data, "LOGOUT");
86213498266Sopenharmony_ci
86313498266Sopenharmony_ci  if(!result)
86413498266Sopenharmony_ci    imap_state(data, IMAP_LOGOUT);
86513498266Sopenharmony_ci
86613498266Sopenharmony_ci  return result;
86713498266Sopenharmony_ci}
86813498266Sopenharmony_ci
86913498266Sopenharmony_ci/* For the initial server greeting */
87013498266Sopenharmony_cistatic CURLcode imap_state_servergreet_resp(struct Curl_easy *data,
87113498266Sopenharmony_ci                                            int imapcode,
87213498266Sopenharmony_ci                                            imapstate instate)
87313498266Sopenharmony_ci{
87413498266Sopenharmony_ci  struct connectdata *conn = data->conn;
87513498266Sopenharmony_ci  (void)instate; /* no use for this yet */
87613498266Sopenharmony_ci
87713498266Sopenharmony_ci  if(imapcode == IMAP_RESP_PREAUTH) {
87813498266Sopenharmony_ci    /* PREAUTH */
87913498266Sopenharmony_ci    struct imap_conn *imapc = &conn->proto.imapc;
88013498266Sopenharmony_ci    imapc->preauth = TRUE;
88113498266Sopenharmony_ci    infof(data, "PREAUTH connection, already authenticated");
88213498266Sopenharmony_ci  }
88313498266Sopenharmony_ci  else if(imapcode != IMAP_RESP_OK) {
88413498266Sopenharmony_ci    failf(data, "Got unexpected imap-server response");
88513498266Sopenharmony_ci    return CURLE_WEIRD_SERVER_REPLY;
88613498266Sopenharmony_ci  }
88713498266Sopenharmony_ci
88813498266Sopenharmony_ci  return imap_perform_capability(data, conn);
88913498266Sopenharmony_ci}
89013498266Sopenharmony_ci
89113498266Sopenharmony_ci/* For CAPABILITY responses */
89213498266Sopenharmony_cistatic CURLcode imap_state_capability_resp(struct Curl_easy *data,
89313498266Sopenharmony_ci                                           int imapcode,
89413498266Sopenharmony_ci                                           imapstate instate)
89513498266Sopenharmony_ci{
89613498266Sopenharmony_ci  CURLcode result = CURLE_OK;
89713498266Sopenharmony_ci  struct connectdata *conn = data->conn;
89813498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
89913498266Sopenharmony_ci  const char *line = Curl_dyn_ptr(&imapc->pp.recvbuf);
90013498266Sopenharmony_ci
90113498266Sopenharmony_ci  (void)instate; /* no use for this yet */
90213498266Sopenharmony_ci
90313498266Sopenharmony_ci  /* Do we have a untagged response? */
90413498266Sopenharmony_ci  if(imapcode == '*') {
90513498266Sopenharmony_ci    line += 2;
90613498266Sopenharmony_ci
90713498266Sopenharmony_ci    /* Loop through the data line */
90813498266Sopenharmony_ci    for(;;) {
90913498266Sopenharmony_ci      size_t wordlen;
91013498266Sopenharmony_ci      while(*line &&
91113498266Sopenharmony_ci            (*line == ' ' || *line == '\t' ||
91213498266Sopenharmony_ci              *line == '\r' || *line == '\n')) {
91313498266Sopenharmony_ci
91413498266Sopenharmony_ci        line++;
91513498266Sopenharmony_ci      }
91613498266Sopenharmony_ci
91713498266Sopenharmony_ci      if(!*line)
91813498266Sopenharmony_ci        break;
91913498266Sopenharmony_ci
92013498266Sopenharmony_ci      /* Extract the word */
92113498266Sopenharmony_ci      for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' &&
92213498266Sopenharmony_ci            line[wordlen] != '\t' && line[wordlen] != '\r' &&
92313498266Sopenharmony_ci            line[wordlen] != '\n';)
92413498266Sopenharmony_ci        wordlen++;
92513498266Sopenharmony_ci
92613498266Sopenharmony_ci      /* Does the server support the STARTTLS capability? */
92713498266Sopenharmony_ci      if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
92813498266Sopenharmony_ci        imapc->tls_supported = TRUE;
92913498266Sopenharmony_ci
93013498266Sopenharmony_ci      /* Has the server explicitly disabled clear text authentication? */
93113498266Sopenharmony_ci      else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
93213498266Sopenharmony_ci        imapc->login_disabled = TRUE;
93313498266Sopenharmony_ci
93413498266Sopenharmony_ci      /* Does the server support the SASL-IR capability? */
93513498266Sopenharmony_ci      else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
93613498266Sopenharmony_ci        imapc->ir_supported = TRUE;
93713498266Sopenharmony_ci
93813498266Sopenharmony_ci      /* Do we have a SASL based authentication mechanism? */
93913498266Sopenharmony_ci      else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
94013498266Sopenharmony_ci        size_t llen;
94113498266Sopenharmony_ci        unsigned short mechbit;
94213498266Sopenharmony_ci
94313498266Sopenharmony_ci        line += 5;
94413498266Sopenharmony_ci        wordlen -= 5;
94513498266Sopenharmony_ci
94613498266Sopenharmony_ci        /* Test the word for a matching authentication mechanism */
94713498266Sopenharmony_ci        mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
94813498266Sopenharmony_ci        if(mechbit && llen == wordlen)
94913498266Sopenharmony_ci          imapc->sasl.authmechs |= mechbit;
95013498266Sopenharmony_ci      }
95113498266Sopenharmony_ci
95213498266Sopenharmony_ci      line += wordlen;
95313498266Sopenharmony_ci    }
95413498266Sopenharmony_ci  }
95513498266Sopenharmony_ci  else if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
95613498266Sopenharmony_ci    /* PREAUTH is not compatible with STARTTLS. */
95713498266Sopenharmony_ci    if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
95813498266Sopenharmony_ci      /* Switch to TLS connection now */
95913498266Sopenharmony_ci      result = imap_perform_starttls(data);
96013498266Sopenharmony_ci    }
96113498266Sopenharmony_ci    else if(data->set.use_ssl <= CURLUSESSL_TRY)
96213498266Sopenharmony_ci      result = imap_perform_authentication(data, conn);
96313498266Sopenharmony_ci    else {
96413498266Sopenharmony_ci      failf(data, "STARTTLS not available.");
96513498266Sopenharmony_ci      result = CURLE_USE_SSL_FAILED;
96613498266Sopenharmony_ci    }
96713498266Sopenharmony_ci  }
96813498266Sopenharmony_ci  else
96913498266Sopenharmony_ci    result = imap_perform_authentication(data, conn);
97013498266Sopenharmony_ci
97113498266Sopenharmony_ci  return result;
97213498266Sopenharmony_ci}
97313498266Sopenharmony_ci
97413498266Sopenharmony_ci/* For STARTTLS responses */
97513498266Sopenharmony_cistatic CURLcode imap_state_starttls_resp(struct Curl_easy *data,
97613498266Sopenharmony_ci                                         int imapcode,
97713498266Sopenharmony_ci                                         imapstate instate)
97813498266Sopenharmony_ci{
97913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
98013498266Sopenharmony_ci  struct connectdata *conn = data->conn;
98113498266Sopenharmony_ci
98213498266Sopenharmony_ci  (void)instate; /* no use for this yet */
98313498266Sopenharmony_ci
98413498266Sopenharmony_ci  /* Pipelining in response is forbidden. */
98513498266Sopenharmony_ci  if(data->conn->proto.imapc.pp.overflow)
98613498266Sopenharmony_ci    return CURLE_WEIRD_SERVER_REPLY;
98713498266Sopenharmony_ci
98813498266Sopenharmony_ci  if(imapcode != IMAP_RESP_OK) {
98913498266Sopenharmony_ci    if(data->set.use_ssl != CURLUSESSL_TRY) {
99013498266Sopenharmony_ci      failf(data, "STARTTLS denied");
99113498266Sopenharmony_ci      result = CURLE_USE_SSL_FAILED;
99213498266Sopenharmony_ci    }
99313498266Sopenharmony_ci    else
99413498266Sopenharmony_ci      result = imap_perform_authentication(data, conn);
99513498266Sopenharmony_ci  }
99613498266Sopenharmony_ci  else
99713498266Sopenharmony_ci    result = imap_perform_upgrade_tls(data, conn);
99813498266Sopenharmony_ci
99913498266Sopenharmony_ci  return result;
100013498266Sopenharmony_ci}
100113498266Sopenharmony_ci
100213498266Sopenharmony_ci/* For SASL authentication responses */
100313498266Sopenharmony_cistatic CURLcode imap_state_auth_resp(struct Curl_easy *data,
100413498266Sopenharmony_ci                                     struct connectdata *conn,
100513498266Sopenharmony_ci                                     int imapcode,
100613498266Sopenharmony_ci                                     imapstate instate)
100713498266Sopenharmony_ci{
100813498266Sopenharmony_ci  CURLcode result = CURLE_OK;
100913498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
101013498266Sopenharmony_ci  saslprogress progress;
101113498266Sopenharmony_ci
101213498266Sopenharmony_ci  (void)instate; /* no use for this yet */
101313498266Sopenharmony_ci
101413498266Sopenharmony_ci  result = Curl_sasl_continue(&imapc->sasl, data, imapcode, &progress);
101513498266Sopenharmony_ci  if(!result)
101613498266Sopenharmony_ci    switch(progress) {
101713498266Sopenharmony_ci    case SASL_DONE:
101813498266Sopenharmony_ci      imap_state(data, IMAP_STOP);  /* Authenticated */
101913498266Sopenharmony_ci      break;
102013498266Sopenharmony_ci    case SASL_IDLE:            /* No mechanism left after cancellation */
102113498266Sopenharmony_ci      if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
102213498266Sopenharmony_ci        /* Perform clear text authentication */
102313498266Sopenharmony_ci        result = imap_perform_login(data, conn);
102413498266Sopenharmony_ci      else {
102513498266Sopenharmony_ci        failf(data, "Authentication cancelled");
102613498266Sopenharmony_ci        result = CURLE_LOGIN_DENIED;
102713498266Sopenharmony_ci      }
102813498266Sopenharmony_ci      break;
102913498266Sopenharmony_ci    default:
103013498266Sopenharmony_ci      break;
103113498266Sopenharmony_ci    }
103213498266Sopenharmony_ci
103313498266Sopenharmony_ci  return result;
103413498266Sopenharmony_ci}
103513498266Sopenharmony_ci
103613498266Sopenharmony_ci/* For LOGIN responses */
103713498266Sopenharmony_cistatic CURLcode imap_state_login_resp(struct Curl_easy *data,
103813498266Sopenharmony_ci                                      int imapcode,
103913498266Sopenharmony_ci                                      imapstate instate)
104013498266Sopenharmony_ci{
104113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
104213498266Sopenharmony_ci  (void)instate; /* no use for this yet */
104313498266Sopenharmony_ci
104413498266Sopenharmony_ci  if(imapcode != IMAP_RESP_OK) {
104513498266Sopenharmony_ci    failf(data, "Access denied. %c", imapcode);
104613498266Sopenharmony_ci    result = CURLE_LOGIN_DENIED;
104713498266Sopenharmony_ci  }
104813498266Sopenharmony_ci  else
104913498266Sopenharmony_ci    /* End of connect phase */
105013498266Sopenharmony_ci    imap_state(data, IMAP_STOP);
105113498266Sopenharmony_ci
105213498266Sopenharmony_ci  return result;
105313498266Sopenharmony_ci}
105413498266Sopenharmony_ci
105513498266Sopenharmony_ci/* For LIST and SEARCH responses */
105613498266Sopenharmony_cistatic CURLcode imap_state_listsearch_resp(struct Curl_easy *data,
105713498266Sopenharmony_ci                                           int imapcode,
105813498266Sopenharmony_ci                                           imapstate instate)
105913498266Sopenharmony_ci{
106013498266Sopenharmony_ci  CURLcode result = CURLE_OK;
106113498266Sopenharmony_ci  char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
106213498266Sopenharmony_ci  size_t len = data->conn->proto.imapc.pp.nfinal;
106313498266Sopenharmony_ci
106413498266Sopenharmony_ci  (void)instate; /* No use for this yet */
106513498266Sopenharmony_ci
106613498266Sopenharmony_ci  if(imapcode == '*')
106713498266Sopenharmony_ci    result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
106813498266Sopenharmony_ci  else if(imapcode != IMAP_RESP_OK)
106913498266Sopenharmony_ci    result = CURLE_QUOTE_ERROR;
107013498266Sopenharmony_ci  else
107113498266Sopenharmony_ci    /* End of DO phase */
107213498266Sopenharmony_ci    imap_state(data, IMAP_STOP);
107313498266Sopenharmony_ci
107413498266Sopenharmony_ci  return result;
107513498266Sopenharmony_ci}
107613498266Sopenharmony_ci
107713498266Sopenharmony_ci/* For SELECT responses */
107813498266Sopenharmony_cistatic CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
107913498266Sopenharmony_ci                                       imapstate instate)
108013498266Sopenharmony_ci{
108113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
108213498266Sopenharmony_ci  struct connectdata *conn = data->conn;
108313498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
108413498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
108513498266Sopenharmony_ci  const char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
108613498266Sopenharmony_ci
108713498266Sopenharmony_ci  (void)instate; /* no use for this yet */
108813498266Sopenharmony_ci
108913498266Sopenharmony_ci  if(imapcode == '*') {
109013498266Sopenharmony_ci    /* See if this is an UIDVALIDITY response */
109113498266Sopenharmony_ci    if(checkprefix("OK [UIDVALIDITY ", line + 2)) {
109213498266Sopenharmony_ci      size_t len = 0;
109313498266Sopenharmony_ci      const char *p = &line[2] + strlen("OK [UIDVALIDITY ");
109413498266Sopenharmony_ci      while((len < 20) && p[len] && ISDIGIT(p[len]))
109513498266Sopenharmony_ci        len++;
109613498266Sopenharmony_ci      if(len && (p[len] == ']')) {
109713498266Sopenharmony_ci        struct dynbuf uid;
109813498266Sopenharmony_ci        Curl_dyn_init(&uid, 20);
109913498266Sopenharmony_ci        if(Curl_dyn_addn(&uid, p, len))
110013498266Sopenharmony_ci          return CURLE_OUT_OF_MEMORY;
110113498266Sopenharmony_ci        Curl_safefree(imapc->mailbox_uidvalidity);
110213498266Sopenharmony_ci        imapc->mailbox_uidvalidity = Curl_dyn_ptr(&uid);
110313498266Sopenharmony_ci      }
110413498266Sopenharmony_ci    }
110513498266Sopenharmony_ci  }
110613498266Sopenharmony_ci  else if(imapcode == IMAP_RESP_OK) {
110713498266Sopenharmony_ci    /* Check if the UIDVALIDITY has been specified and matches */
110813498266Sopenharmony_ci    if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
110913498266Sopenharmony_ci       !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
111013498266Sopenharmony_ci      failf(data, "Mailbox UIDVALIDITY has changed");
111113498266Sopenharmony_ci      result = CURLE_REMOTE_FILE_NOT_FOUND;
111213498266Sopenharmony_ci    }
111313498266Sopenharmony_ci    else {
111413498266Sopenharmony_ci      /* Note the currently opened mailbox on this connection */
111513498266Sopenharmony_ci      DEBUGASSERT(!imapc->mailbox);
111613498266Sopenharmony_ci      imapc->mailbox = strdup(imap->mailbox);
111713498266Sopenharmony_ci      if(!imapc->mailbox)
111813498266Sopenharmony_ci        return CURLE_OUT_OF_MEMORY;
111913498266Sopenharmony_ci
112013498266Sopenharmony_ci      if(imap->custom)
112113498266Sopenharmony_ci        result = imap_perform_list(data);
112213498266Sopenharmony_ci      else if(imap->query)
112313498266Sopenharmony_ci        result = imap_perform_search(data);
112413498266Sopenharmony_ci      else
112513498266Sopenharmony_ci        result = imap_perform_fetch(data);
112613498266Sopenharmony_ci    }
112713498266Sopenharmony_ci  }
112813498266Sopenharmony_ci  else {
112913498266Sopenharmony_ci    failf(data, "Select failed");
113013498266Sopenharmony_ci    result = CURLE_LOGIN_DENIED;
113113498266Sopenharmony_ci  }
113213498266Sopenharmony_ci
113313498266Sopenharmony_ci  return result;
113413498266Sopenharmony_ci}
113513498266Sopenharmony_ci
113613498266Sopenharmony_ci/* For the (first line of the) FETCH responses */
113713498266Sopenharmony_cistatic CURLcode imap_state_fetch_resp(struct Curl_easy *data,
113813498266Sopenharmony_ci                                      struct connectdata *conn, int imapcode,
113913498266Sopenharmony_ci                                      imapstate instate)
114013498266Sopenharmony_ci{
114113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
114213498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
114313498266Sopenharmony_ci  struct pingpong *pp = &imapc->pp;
114413498266Sopenharmony_ci  const char *ptr = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
114513498266Sopenharmony_ci  size_t len = data->conn->proto.imapc.pp.nfinal;
114613498266Sopenharmony_ci  bool parsed = FALSE;
114713498266Sopenharmony_ci  curl_off_t size = 0;
114813498266Sopenharmony_ci
114913498266Sopenharmony_ci  (void)instate; /* no use for this yet */
115013498266Sopenharmony_ci
115113498266Sopenharmony_ci  if(imapcode != '*') {
115213498266Sopenharmony_ci    Curl_pgrsSetDownloadSize(data, -1);
115313498266Sopenharmony_ci    imap_state(data, IMAP_STOP);
115413498266Sopenharmony_ci    return CURLE_REMOTE_FILE_NOT_FOUND;
115513498266Sopenharmony_ci  }
115613498266Sopenharmony_ci
115713498266Sopenharmony_ci  /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse
115813498266Sopenharmony_ci     the continuation data contained within the curly brackets */
115913498266Sopenharmony_ci  ptr = memchr(ptr, '{', len);
116013498266Sopenharmony_ci  if(ptr) {
116113498266Sopenharmony_ci    char *endptr;
116213498266Sopenharmony_ci    if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) &&
116313498266Sopenharmony_ci       (endptr - ptr > 1 && *endptr == '}'))
116413498266Sopenharmony_ci      parsed = TRUE;
116513498266Sopenharmony_ci  }
116613498266Sopenharmony_ci
116713498266Sopenharmony_ci  if(parsed) {
116813498266Sopenharmony_ci    infof(data, "Found %" CURL_FORMAT_CURL_OFF_T " bytes to download",
116913498266Sopenharmony_ci          size);
117013498266Sopenharmony_ci    Curl_pgrsSetDownloadSize(data, size);
117113498266Sopenharmony_ci
117213498266Sopenharmony_ci    if(pp->overflow) {
117313498266Sopenharmony_ci      /* At this point there is a data in the receive buffer that is body
117413498266Sopenharmony_ci         content, send it as body and then skip it. Do note that there may
117513498266Sopenharmony_ci         even be additional "headers" after the body. */
117613498266Sopenharmony_ci      size_t chunk = pp->overflow;
117713498266Sopenharmony_ci
117813498266Sopenharmony_ci      /* keep only the overflow */
117913498266Sopenharmony_ci      Curl_dyn_tail(&pp->recvbuf, chunk);
118013498266Sopenharmony_ci      pp->nfinal = 0; /* done */
118113498266Sopenharmony_ci
118213498266Sopenharmony_ci      if(chunk > (size_t)size)
118313498266Sopenharmony_ci        /* The conversion from curl_off_t to size_t is always fine here */
118413498266Sopenharmony_ci        chunk = (size_t)size;
118513498266Sopenharmony_ci
118613498266Sopenharmony_ci      if(!chunk) {
118713498266Sopenharmony_ci        /* no size, we're done with the data */
118813498266Sopenharmony_ci        imap_state(data, IMAP_STOP);
118913498266Sopenharmony_ci        return CURLE_OK;
119013498266Sopenharmony_ci      }
119113498266Sopenharmony_ci      result = Curl_client_write(data, CLIENTWRITE_BODY,
119213498266Sopenharmony_ci                                 Curl_dyn_ptr(&pp->recvbuf), chunk);
119313498266Sopenharmony_ci      if(result)
119413498266Sopenharmony_ci        return result;
119513498266Sopenharmony_ci
119613498266Sopenharmony_ci      infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU
119713498266Sopenharmony_ci            " bytes are left for transfer", chunk, size - chunk);
119813498266Sopenharmony_ci
119913498266Sopenharmony_ci      /* Have we used the entire overflow or just part of it?*/
120013498266Sopenharmony_ci      if(pp->overflow > chunk) {
120113498266Sopenharmony_ci        /* remember the remaining trailing overflow data */
120213498266Sopenharmony_ci        pp->overflow -= chunk;
120313498266Sopenharmony_ci        Curl_dyn_tail(&pp->recvbuf, pp->overflow);
120413498266Sopenharmony_ci      }
120513498266Sopenharmony_ci      else {
120613498266Sopenharmony_ci        pp->overflow = 0; /* handled */
120713498266Sopenharmony_ci        /* Free the cache */
120813498266Sopenharmony_ci        Curl_dyn_reset(&pp->recvbuf);
120913498266Sopenharmony_ci      }
121013498266Sopenharmony_ci    }
121113498266Sopenharmony_ci
121213498266Sopenharmony_ci    if(data->req.bytecount == size)
121313498266Sopenharmony_ci      /* The entire data is already transferred! */
121413498266Sopenharmony_ci      Curl_setup_transfer(data, -1, -1, FALSE, -1);
121513498266Sopenharmony_ci    else {
121613498266Sopenharmony_ci      /* IMAP download */
121713498266Sopenharmony_ci      data->req.maxdownload = size;
121813498266Sopenharmony_ci      /* force a recv/send check of this connection, as the data might've been
121913498266Sopenharmony_ci       read off the socket already */
122013498266Sopenharmony_ci      data->state.select_bits = CURL_CSELECT_IN;
122113498266Sopenharmony_ci      Curl_setup_transfer(data, FIRSTSOCKET, size, FALSE, -1);
122213498266Sopenharmony_ci    }
122313498266Sopenharmony_ci  }
122413498266Sopenharmony_ci  else {
122513498266Sopenharmony_ci    /* We don't know how to parse this line */
122613498266Sopenharmony_ci    failf(data, "Failed to parse FETCH response.");
122713498266Sopenharmony_ci    result = CURLE_WEIRD_SERVER_REPLY;
122813498266Sopenharmony_ci  }
122913498266Sopenharmony_ci
123013498266Sopenharmony_ci  /* End of DO phase */
123113498266Sopenharmony_ci  imap_state(data, IMAP_STOP);
123213498266Sopenharmony_ci
123313498266Sopenharmony_ci  return result;
123413498266Sopenharmony_ci}
123513498266Sopenharmony_ci
123613498266Sopenharmony_ci/* For final FETCH responses performed after the download */
123713498266Sopenharmony_cistatic CURLcode imap_state_fetch_final_resp(struct Curl_easy *data,
123813498266Sopenharmony_ci                                            int imapcode,
123913498266Sopenharmony_ci                                            imapstate instate)
124013498266Sopenharmony_ci{
124113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
124213498266Sopenharmony_ci
124313498266Sopenharmony_ci  (void)instate; /* No use for this yet */
124413498266Sopenharmony_ci
124513498266Sopenharmony_ci  if(imapcode != IMAP_RESP_OK)
124613498266Sopenharmony_ci    result = CURLE_WEIRD_SERVER_REPLY;
124713498266Sopenharmony_ci  else
124813498266Sopenharmony_ci    /* End of DONE phase */
124913498266Sopenharmony_ci    imap_state(data, IMAP_STOP);
125013498266Sopenharmony_ci
125113498266Sopenharmony_ci  return result;
125213498266Sopenharmony_ci}
125313498266Sopenharmony_ci
125413498266Sopenharmony_ci/* For APPEND responses */
125513498266Sopenharmony_cistatic CURLcode imap_state_append_resp(struct Curl_easy *data, int imapcode,
125613498266Sopenharmony_ci                                       imapstate instate)
125713498266Sopenharmony_ci{
125813498266Sopenharmony_ci  CURLcode result = CURLE_OK;
125913498266Sopenharmony_ci  (void)instate; /* No use for this yet */
126013498266Sopenharmony_ci
126113498266Sopenharmony_ci  if(imapcode != '+') {
126213498266Sopenharmony_ci    result = CURLE_UPLOAD_FAILED;
126313498266Sopenharmony_ci  }
126413498266Sopenharmony_ci  else {
126513498266Sopenharmony_ci    /* Set the progress upload size */
126613498266Sopenharmony_ci    Curl_pgrsSetUploadSize(data, data->state.infilesize);
126713498266Sopenharmony_ci
126813498266Sopenharmony_ci    /* IMAP upload */
126913498266Sopenharmony_ci    Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
127013498266Sopenharmony_ci
127113498266Sopenharmony_ci    /* End of DO phase */
127213498266Sopenharmony_ci    imap_state(data, IMAP_STOP);
127313498266Sopenharmony_ci  }
127413498266Sopenharmony_ci
127513498266Sopenharmony_ci  return result;
127613498266Sopenharmony_ci}
127713498266Sopenharmony_ci
127813498266Sopenharmony_ci/* For final APPEND responses performed after the upload */
127913498266Sopenharmony_cistatic CURLcode imap_state_append_final_resp(struct Curl_easy *data,
128013498266Sopenharmony_ci                                             int imapcode,
128113498266Sopenharmony_ci                                             imapstate instate)
128213498266Sopenharmony_ci{
128313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
128413498266Sopenharmony_ci
128513498266Sopenharmony_ci  (void)instate; /* No use for this yet */
128613498266Sopenharmony_ci
128713498266Sopenharmony_ci  if(imapcode != IMAP_RESP_OK)
128813498266Sopenharmony_ci    result = CURLE_UPLOAD_FAILED;
128913498266Sopenharmony_ci  else
129013498266Sopenharmony_ci    /* End of DONE phase */
129113498266Sopenharmony_ci    imap_state(data, IMAP_STOP);
129213498266Sopenharmony_ci
129313498266Sopenharmony_ci  return result;
129413498266Sopenharmony_ci}
129513498266Sopenharmony_ci
129613498266Sopenharmony_cistatic CURLcode imap_statemachine(struct Curl_easy *data,
129713498266Sopenharmony_ci                                  struct connectdata *conn)
129813498266Sopenharmony_ci{
129913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
130013498266Sopenharmony_ci  curl_socket_t sock = conn->sock[FIRSTSOCKET];
130113498266Sopenharmony_ci  int imapcode;
130213498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
130313498266Sopenharmony_ci  struct pingpong *pp = &imapc->pp;
130413498266Sopenharmony_ci  size_t nread = 0;
130513498266Sopenharmony_ci  (void)data;
130613498266Sopenharmony_ci
130713498266Sopenharmony_ci  /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */
130813498266Sopenharmony_ci  if(imapc->state == IMAP_UPGRADETLS)
130913498266Sopenharmony_ci    return imap_perform_upgrade_tls(data, conn);
131013498266Sopenharmony_ci
131113498266Sopenharmony_ci  /* Flush any data that needs to be sent */
131213498266Sopenharmony_ci  if(pp->sendleft)
131313498266Sopenharmony_ci    return Curl_pp_flushsend(data, pp);
131413498266Sopenharmony_ci
131513498266Sopenharmony_ci  do {
131613498266Sopenharmony_ci    /* Read the response from the server */
131713498266Sopenharmony_ci    result = Curl_pp_readresp(data, sock, pp, &imapcode, &nread);
131813498266Sopenharmony_ci    if(result)
131913498266Sopenharmony_ci      return result;
132013498266Sopenharmony_ci
132113498266Sopenharmony_ci    /* Was there an error parsing the response line? */
132213498266Sopenharmony_ci    if(imapcode == -1)
132313498266Sopenharmony_ci      return CURLE_WEIRD_SERVER_REPLY;
132413498266Sopenharmony_ci
132513498266Sopenharmony_ci    if(!imapcode)
132613498266Sopenharmony_ci      break;
132713498266Sopenharmony_ci
132813498266Sopenharmony_ci    /* We have now received a full IMAP server response */
132913498266Sopenharmony_ci    switch(imapc->state) {
133013498266Sopenharmony_ci    case IMAP_SERVERGREET:
133113498266Sopenharmony_ci      result = imap_state_servergreet_resp(data, imapcode, imapc->state);
133213498266Sopenharmony_ci      break;
133313498266Sopenharmony_ci
133413498266Sopenharmony_ci    case IMAP_CAPABILITY:
133513498266Sopenharmony_ci      result = imap_state_capability_resp(data, imapcode, imapc->state);
133613498266Sopenharmony_ci      break;
133713498266Sopenharmony_ci
133813498266Sopenharmony_ci    case IMAP_STARTTLS:
133913498266Sopenharmony_ci      result = imap_state_starttls_resp(data, imapcode, imapc->state);
134013498266Sopenharmony_ci      break;
134113498266Sopenharmony_ci
134213498266Sopenharmony_ci    case IMAP_AUTHENTICATE:
134313498266Sopenharmony_ci      result = imap_state_auth_resp(data, conn, imapcode, imapc->state);
134413498266Sopenharmony_ci      break;
134513498266Sopenharmony_ci
134613498266Sopenharmony_ci    case IMAP_LOGIN:
134713498266Sopenharmony_ci      result = imap_state_login_resp(data, imapcode, imapc->state);
134813498266Sopenharmony_ci      break;
134913498266Sopenharmony_ci
135013498266Sopenharmony_ci    case IMAP_LIST:
135113498266Sopenharmony_ci    case IMAP_SEARCH:
135213498266Sopenharmony_ci      result = imap_state_listsearch_resp(data, imapcode, imapc->state);
135313498266Sopenharmony_ci      break;
135413498266Sopenharmony_ci
135513498266Sopenharmony_ci    case IMAP_SELECT:
135613498266Sopenharmony_ci      result = imap_state_select_resp(data, imapcode, imapc->state);
135713498266Sopenharmony_ci      break;
135813498266Sopenharmony_ci
135913498266Sopenharmony_ci    case IMAP_FETCH:
136013498266Sopenharmony_ci      result = imap_state_fetch_resp(data, conn, imapcode, imapc->state);
136113498266Sopenharmony_ci      break;
136213498266Sopenharmony_ci
136313498266Sopenharmony_ci    case IMAP_FETCH_FINAL:
136413498266Sopenharmony_ci      result = imap_state_fetch_final_resp(data, imapcode, imapc->state);
136513498266Sopenharmony_ci      break;
136613498266Sopenharmony_ci
136713498266Sopenharmony_ci    case IMAP_APPEND:
136813498266Sopenharmony_ci      result = imap_state_append_resp(data, imapcode, imapc->state);
136913498266Sopenharmony_ci      break;
137013498266Sopenharmony_ci
137113498266Sopenharmony_ci    case IMAP_APPEND_FINAL:
137213498266Sopenharmony_ci      result = imap_state_append_final_resp(data, imapcode, imapc->state);
137313498266Sopenharmony_ci      break;
137413498266Sopenharmony_ci
137513498266Sopenharmony_ci    case IMAP_LOGOUT:
137613498266Sopenharmony_ci    default:
137713498266Sopenharmony_ci      /* internal error */
137813498266Sopenharmony_ci      imap_state(data, IMAP_STOP);
137913498266Sopenharmony_ci      break;
138013498266Sopenharmony_ci    }
138113498266Sopenharmony_ci  } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp));
138213498266Sopenharmony_ci
138313498266Sopenharmony_ci  return result;
138413498266Sopenharmony_ci}
138513498266Sopenharmony_ci
138613498266Sopenharmony_ci/* Called repeatedly until done from multi.c */
138713498266Sopenharmony_cistatic CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done)
138813498266Sopenharmony_ci{
138913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
139013498266Sopenharmony_ci  struct connectdata *conn = data->conn;
139113498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
139213498266Sopenharmony_ci
139313498266Sopenharmony_ci  if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
139413498266Sopenharmony_ci    bool ssldone = FALSE;
139513498266Sopenharmony_ci    result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
139613498266Sopenharmony_ci    imapc->ssldone = ssldone;
139713498266Sopenharmony_ci    if(result || !ssldone)
139813498266Sopenharmony_ci      return result;
139913498266Sopenharmony_ci  }
140013498266Sopenharmony_ci
140113498266Sopenharmony_ci  result = Curl_pp_statemach(data, &imapc->pp, FALSE, FALSE);
140213498266Sopenharmony_ci  *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
140313498266Sopenharmony_ci
140413498266Sopenharmony_ci  return result;
140513498266Sopenharmony_ci}
140613498266Sopenharmony_ci
140713498266Sopenharmony_cistatic CURLcode imap_block_statemach(struct Curl_easy *data,
140813498266Sopenharmony_ci                                     struct connectdata *conn,
140913498266Sopenharmony_ci                                     bool disconnecting)
141013498266Sopenharmony_ci{
141113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
141213498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
141313498266Sopenharmony_ci
141413498266Sopenharmony_ci  while(imapc->state != IMAP_STOP && !result)
141513498266Sopenharmony_ci    result = Curl_pp_statemach(data, &imapc->pp, TRUE, disconnecting);
141613498266Sopenharmony_ci
141713498266Sopenharmony_ci  return result;
141813498266Sopenharmony_ci}
141913498266Sopenharmony_ci
142013498266Sopenharmony_ci/* Allocate and initialize the struct IMAP for the current Curl_easy if
142113498266Sopenharmony_ci   required */
142213498266Sopenharmony_cistatic CURLcode imap_init(struct Curl_easy *data)
142313498266Sopenharmony_ci{
142413498266Sopenharmony_ci  CURLcode result = CURLE_OK;
142513498266Sopenharmony_ci  struct IMAP *imap;
142613498266Sopenharmony_ci
142713498266Sopenharmony_ci  imap = data->req.p.imap = calloc(1, sizeof(struct IMAP));
142813498266Sopenharmony_ci  if(!imap)
142913498266Sopenharmony_ci    result = CURLE_OUT_OF_MEMORY;
143013498266Sopenharmony_ci
143113498266Sopenharmony_ci  return result;
143213498266Sopenharmony_ci}
143313498266Sopenharmony_ci
143413498266Sopenharmony_ci/* For the IMAP "protocol connect" and "doing" phases only */
143513498266Sopenharmony_cistatic int imap_getsock(struct Curl_easy *data,
143613498266Sopenharmony_ci                        struct connectdata *conn,
143713498266Sopenharmony_ci                        curl_socket_t *socks)
143813498266Sopenharmony_ci{
143913498266Sopenharmony_ci  return Curl_pp_getsock(data, &conn->proto.imapc.pp, socks);
144013498266Sopenharmony_ci}
144113498266Sopenharmony_ci
144213498266Sopenharmony_ci/***********************************************************************
144313498266Sopenharmony_ci *
144413498266Sopenharmony_ci * imap_connect()
144513498266Sopenharmony_ci *
144613498266Sopenharmony_ci * This function should do everything that is to be considered a part of the
144713498266Sopenharmony_ci * connection phase.
144813498266Sopenharmony_ci *
144913498266Sopenharmony_ci * The variable 'done' points to will be TRUE if the protocol-layer connect
145013498266Sopenharmony_ci * phase is done when this function returns, or FALSE if not.
145113498266Sopenharmony_ci */
145213498266Sopenharmony_cistatic CURLcode imap_connect(struct Curl_easy *data, bool *done)
145313498266Sopenharmony_ci{
145413498266Sopenharmony_ci  CURLcode result = CURLE_OK;
145513498266Sopenharmony_ci  struct connectdata *conn = data->conn;
145613498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
145713498266Sopenharmony_ci  struct pingpong *pp = &imapc->pp;
145813498266Sopenharmony_ci
145913498266Sopenharmony_ci  *done = FALSE; /* default to not done yet */
146013498266Sopenharmony_ci
146113498266Sopenharmony_ci  /* We always support persistent connections in IMAP */
146213498266Sopenharmony_ci  connkeep(conn, "IMAP default");
146313498266Sopenharmony_ci
146413498266Sopenharmony_ci  PINGPONG_SETUP(pp, imap_statemachine, imap_endofresp);
146513498266Sopenharmony_ci
146613498266Sopenharmony_ci  /* Set the default preferred authentication type and mechanism */
146713498266Sopenharmony_ci  imapc->preftype = IMAP_TYPE_ANY;
146813498266Sopenharmony_ci  Curl_sasl_init(&imapc->sasl, data, &saslimap);
146913498266Sopenharmony_ci
147013498266Sopenharmony_ci  Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
147113498266Sopenharmony_ci  Curl_pp_init(pp);
147213498266Sopenharmony_ci
147313498266Sopenharmony_ci  /* Parse the URL options */
147413498266Sopenharmony_ci  result = imap_parse_url_options(conn);
147513498266Sopenharmony_ci  if(result)
147613498266Sopenharmony_ci    return result;
147713498266Sopenharmony_ci
147813498266Sopenharmony_ci  /* Start off waiting for the server greeting response */
147913498266Sopenharmony_ci  imap_state(data, IMAP_SERVERGREET);
148013498266Sopenharmony_ci
148113498266Sopenharmony_ci  /* Start off with an response id of '*' */
148213498266Sopenharmony_ci  strcpy(imapc->resptag, "*");
148313498266Sopenharmony_ci
148413498266Sopenharmony_ci  result = imap_multi_statemach(data, done);
148513498266Sopenharmony_ci
148613498266Sopenharmony_ci  return result;
148713498266Sopenharmony_ci}
148813498266Sopenharmony_ci
148913498266Sopenharmony_ci/***********************************************************************
149013498266Sopenharmony_ci *
149113498266Sopenharmony_ci * imap_done()
149213498266Sopenharmony_ci *
149313498266Sopenharmony_ci * The DONE function. This does what needs to be done after a single DO has
149413498266Sopenharmony_ci * performed.
149513498266Sopenharmony_ci *
149613498266Sopenharmony_ci * Input argument is already checked for validity.
149713498266Sopenharmony_ci */
149813498266Sopenharmony_cistatic CURLcode imap_done(struct Curl_easy *data, CURLcode status,
149913498266Sopenharmony_ci                          bool premature)
150013498266Sopenharmony_ci{
150113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
150213498266Sopenharmony_ci  struct connectdata *conn = data->conn;
150313498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
150413498266Sopenharmony_ci
150513498266Sopenharmony_ci  (void)premature;
150613498266Sopenharmony_ci
150713498266Sopenharmony_ci  if(!imap)
150813498266Sopenharmony_ci    return CURLE_OK;
150913498266Sopenharmony_ci
151013498266Sopenharmony_ci  if(status) {
151113498266Sopenharmony_ci    connclose(conn, "IMAP done with bad status"); /* marked for closure */
151213498266Sopenharmony_ci    result = status;         /* use the already set error code */
151313498266Sopenharmony_ci  }
151413498266Sopenharmony_ci  else if(!data->set.connect_only && !imap->custom &&
151513498266Sopenharmony_ci          (imap->uid || imap->mindex || data->state.upload ||
151613498266Sopenharmony_ci          data->set.mimepost.kind != MIMEKIND_NONE)) {
151713498266Sopenharmony_ci    /* Handle responses after FETCH or APPEND transfer has finished */
151813498266Sopenharmony_ci
151913498266Sopenharmony_ci    if(!data->state.upload && data->set.mimepost.kind == MIMEKIND_NONE)
152013498266Sopenharmony_ci      imap_state(data, IMAP_FETCH_FINAL);
152113498266Sopenharmony_ci    else {
152213498266Sopenharmony_ci      /* End the APPEND command first by sending an empty line */
152313498266Sopenharmony_ci      result = Curl_pp_sendf(data, &conn->proto.imapc.pp, "%s", "");
152413498266Sopenharmony_ci      if(!result)
152513498266Sopenharmony_ci        imap_state(data, IMAP_APPEND_FINAL);
152613498266Sopenharmony_ci    }
152713498266Sopenharmony_ci
152813498266Sopenharmony_ci    /* Run the state-machine */
152913498266Sopenharmony_ci    if(!result)
153013498266Sopenharmony_ci      result = imap_block_statemach(data, conn, FALSE);
153113498266Sopenharmony_ci  }
153213498266Sopenharmony_ci
153313498266Sopenharmony_ci  /* Cleanup our per-request based variables */
153413498266Sopenharmony_ci  Curl_safefree(imap->mailbox);
153513498266Sopenharmony_ci  Curl_safefree(imap->uidvalidity);
153613498266Sopenharmony_ci  Curl_safefree(imap->uid);
153713498266Sopenharmony_ci  Curl_safefree(imap->mindex);
153813498266Sopenharmony_ci  Curl_safefree(imap->section);
153913498266Sopenharmony_ci  Curl_safefree(imap->partial);
154013498266Sopenharmony_ci  Curl_safefree(imap->query);
154113498266Sopenharmony_ci  Curl_safefree(imap->custom);
154213498266Sopenharmony_ci  Curl_safefree(imap->custom_params);
154313498266Sopenharmony_ci
154413498266Sopenharmony_ci  /* Clear the transfer mode for the next request */
154513498266Sopenharmony_ci  imap->transfer = PPTRANSFER_BODY;
154613498266Sopenharmony_ci
154713498266Sopenharmony_ci  return result;
154813498266Sopenharmony_ci}
154913498266Sopenharmony_ci
155013498266Sopenharmony_ci/***********************************************************************
155113498266Sopenharmony_ci *
155213498266Sopenharmony_ci * imap_perform()
155313498266Sopenharmony_ci *
155413498266Sopenharmony_ci * This is the actual DO function for IMAP. Fetch or append a message, or do
155513498266Sopenharmony_ci * other things according to the options previously setup.
155613498266Sopenharmony_ci */
155713498266Sopenharmony_cistatic CURLcode imap_perform(struct Curl_easy *data, bool *connected,
155813498266Sopenharmony_ci                             bool *dophase_done)
155913498266Sopenharmony_ci{
156013498266Sopenharmony_ci  /* This is IMAP and no proxy */
156113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
156213498266Sopenharmony_ci  struct connectdata *conn = data->conn;
156313498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
156413498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
156513498266Sopenharmony_ci  bool selected = FALSE;
156613498266Sopenharmony_ci
156713498266Sopenharmony_ci  DEBUGF(infof(data, "DO phase starts"));
156813498266Sopenharmony_ci
156913498266Sopenharmony_ci  if(data->req.no_body) {
157013498266Sopenharmony_ci    /* Requested no body means no transfer */
157113498266Sopenharmony_ci    imap->transfer = PPTRANSFER_INFO;
157213498266Sopenharmony_ci  }
157313498266Sopenharmony_ci
157413498266Sopenharmony_ci  *dophase_done = FALSE; /* not done yet */
157513498266Sopenharmony_ci
157613498266Sopenharmony_ci  /* Determine if the requested mailbox (with the same UIDVALIDITY if set)
157713498266Sopenharmony_ci     has already been selected on this connection */
157813498266Sopenharmony_ci  if(imap->mailbox && imapc->mailbox &&
157913498266Sopenharmony_ci     strcasecompare(imap->mailbox, imapc->mailbox) &&
158013498266Sopenharmony_ci     (!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
158113498266Sopenharmony_ci      strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)))
158213498266Sopenharmony_ci    selected = TRUE;
158313498266Sopenharmony_ci
158413498266Sopenharmony_ci  /* Start the first command in the DO phase */
158513498266Sopenharmony_ci  if(data->state.upload || data->set.mimepost.kind != MIMEKIND_NONE)
158613498266Sopenharmony_ci    /* APPEND can be executed directly */
158713498266Sopenharmony_ci    result = imap_perform_append(data);
158813498266Sopenharmony_ci  else if(imap->custom && (selected || !imap->mailbox))
158913498266Sopenharmony_ci    /* Custom command using the same mailbox or no mailbox */
159013498266Sopenharmony_ci    result = imap_perform_list(data);
159113498266Sopenharmony_ci  else if(!imap->custom && selected && (imap->uid || imap->mindex))
159213498266Sopenharmony_ci    /* FETCH from the same mailbox */
159313498266Sopenharmony_ci    result = imap_perform_fetch(data);
159413498266Sopenharmony_ci  else if(!imap->custom && selected && imap->query)
159513498266Sopenharmony_ci    /* SEARCH the current mailbox */
159613498266Sopenharmony_ci    result = imap_perform_search(data);
159713498266Sopenharmony_ci  else if(imap->mailbox && !selected &&
159813498266Sopenharmony_ci         (imap->custom || imap->uid || imap->mindex || imap->query))
159913498266Sopenharmony_ci    /* SELECT the mailbox */
160013498266Sopenharmony_ci    result = imap_perform_select(data);
160113498266Sopenharmony_ci  else
160213498266Sopenharmony_ci    /* LIST */
160313498266Sopenharmony_ci    result = imap_perform_list(data);
160413498266Sopenharmony_ci
160513498266Sopenharmony_ci  if(result)
160613498266Sopenharmony_ci    return result;
160713498266Sopenharmony_ci
160813498266Sopenharmony_ci  /* Run the state-machine */
160913498266Sopenharmony_ci  result = imap_multi_statemach(data, dophase_done);
161013498266Sopenharmony_ci
161113498266Sopenharmony_ci  *connected = Curl_conn_is_connected(conn, FIRSTSOCKET);
161213498266Sopenharmony_ci
161313498266Sopenharmony_ci  if(*dophase_done)
161413498266Sopenharmony_ci    DEBUGF(infof(data, "DO phase is complete"));
161513498266Sopenharmony_ci
161613498266Sopenharmony_ci  return result;
161713498266Sopenharmony_ci}
161813498266Sopenharmony_ci
161913498266Sopenharmony_ci/***********************************************************************
162013498266Sopenharmony_ci *
162113498266Sopenharmony_ci * imap_do()
162213498266Sopenharmony_ci *
162313498266Sopenharmony_ci * This function is registered as 'curl_do' function. It decodes the path
162413498266Sopenharmony_ci * parts etc as a wrapper to the actual DO function (imap_perform).
162513498266Sopenharmony_ci *
162613498266Sopenharmony_ci * The input argument is already checked for validity.
162713498266Sopenharmony_ci */
162813498266Sopenharmony_cistatic CURLcode imap_do(struct Curl_easy *data, bool *done)
162913498266Sopenharmony_ci{
163013498266Sopenharmony_ci  CURLcode result = CURLE_OK;
163113498266Sopenharmony_ci  *done = FALSE; /* default to false */
163213498266Sopenharmony_ci
163313498266Sopenharmony_ci  /* Parse the URL path */
163413498266Sopenharmony_ci  result = imap_parse_url_path(data);
163513498266Sopenharmony_ci  if(result)
163613498266Sopenharmony_ci    return result;
163713498266Sopenharmony_ci
163813498266Sopenharmony_ci  /* Parse the custom request */
163913498266Sopenharmony_ci  result = imap_parse_custom_request(data);
164013498266Sopenharmony_ci  if(result)
164113498266Sopenharmony_ci    return result;
164213498266Sopenharmony_ci
164313498266Sopenharmony_ci  result = imap_regular_transfer(data, done);
164413498266Sopenharmony_ci
164513498266Sopenharmony_ci  return result;
164613498266Sopenharmony_ci}
164713498266Sopenharmony_ci
164813498266Sopenharmony_ci/***********************************************************************
164913498266Sopenharmony_ci *
165013498266Sopenharmony_ci * imap_disconnect()
165113498266Sopenharmony_ci *
165213498266Sopenharmony_ci * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
165313498266Sopenharmony_ci * resources. BLOCKING.
165413498266Sopenharmony_ci */
165513498266Sopenharmony_cistatic CURLcode imap_disconnect(struct Curl_easy *data,
165613498266Sopenharmony_ci                                struct connectdata *conn, bool dead_connection)
165713498266Sopenharmony_ci{
165813498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
165913498266Sopenharmony_ci  (void)data;
166013498266Sopenharmony_ci
166113498266Sopenharmony_ci  /* We cannot send quit unconditionally. If this connection is stale or
166213498266Sopenharmony_ci     bad in any way, sending quit and waiting around here will make the
166313498266Sopenharmony_ci     disconnect wait in vain and cause more problems than we need to. */
166413498266Sopenharmony_ci
166513498266Sopenharmony_ci  /* The IMAP session may or may not have been allocated/setup at this
166613498266Sopenharmony_ci     point! */
166713498266Sopenharmony_ci  if(!dead_connection && conn->bits.protoconnstart) {
166813498266Sopenharmony_ci    if(!imap_perform_logout(data))
166913498266Sopenharmony_ci      (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */
167013498266Sopenharmony_ci  }
167113498266Sopenharmony_ci
167213498266Sopenharmony_ci  /* Disconnect from the server */
167313498266Sopenharmony_ci  Curl_pp_disconnect(&imapc->pp);
167413498266Sopenharmony_ci  Curl_dyn_free(&imapc->dyn);
167513498266Sopenharmony_ci
167613498266Sopenharmony_ci  /* Cleanup the SASL module */
167713498266Sopenharmony_ci  Curl_sasl_cleanup(conn, imapc->sasl.authused);
167813498266Sopenharmony_ci
167913498266Sopenharmony_ci  /* Cleanup our connection based variables */
168013498266Sopenharmony_ci  Curl_safefree(imapc->mailbox);
168113498266Sopenharmony_ci  Curl_safefree(imapc->mailbox_uidvalidity);
168213498266Sopenharmony_ci
168313498266Sopenharmony_ci  return CURLE_OK;
168413498266Sopenharmony_ci}
168513498266Sopenharmony_ci
168613498266Sopenharmony_ci/* Call this when the DO phase has completed */
168713498266Sopenharmony_cistatic CURLcode imap_dophase_done(struct Curl_easy *data, bool connected)
168813498266Sopenharmony_ci{
168913498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
169013498266Sopenharmony_ci
169113498266Sopenharmony_ci  (void)connected;
169213498266Sopenharmony_ci
169313498266Sopenharmony_ci  if(imap->transfer != PPTRANSFER_BODY)
169413498266Sopenharmony_ci    /* no data to transfer */
169513498266Sopenharmony_ci    Curl_setup_transfer(data, -1, -1, FALSE, -1);
169613498266Sopenharmony_ci
169713498266Sopenharmony_ci  return CURLE_OK;
169813498266Sopenharmony_ci}
169913498266Sopenharmony_ci
170013498266Sopenharmony_ci/* Called from multi.c while DOing */
170113498266Sopenharmony_cistatic CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done)
170213498266Sopenharmony_ci{
170313498266Sopenharmony_ci  CURLcode result = imap_multi_statemach(data, dophase_done);
170413498266Sopenharmony_ci
170513498266Sopenharmony_ci  if(result)
170613498266Sopenharmony_ci    DEBUGF(infof(data, "DO phase failed"));
170713498266Sopenharmony_ci  else if(*dophase_done) {
170813498266Sopenharmony_ci    result = imap_dophase_done(data, FALSE /* not connected */);
170913498266Sopenharmony_ci
171013498266Sopenharmony_ci    DEBUGF(infof(data, "DO phase is complete"));
171113498266Sopenharmony_ci  }
171213498266Sopenharmony_ci
171313498266Sopenharmony_ci  return result;
171413498266Sopenharmony_ci}
171513498266Sopenharmony_ci
171613498266Sopenharmony_ci/***********************************************************************
171713498266Sopenharmony_ci *
171813498266Sopenharmony_ci * imap_regular_transfer()
171913498266Sopenharmony_ci *
172013498266Sopenharmony_ci * The input argument is already checked for validity.
172113498266Sopenharmony_ci *
172213498266Sopenharmony_ci * Performs all commands done before a regular transfer between a local and a
172313498266Sopenharmony_ci * remote host.
172413498266Sopenharmony_ci */
172513498266Sopenharmony_cistatic CURLcode imap_regular_transfer(struct Curl_easy *data,
172613498266Sopenharmony_ci                                      bool *dophase_done)
172713498266Sopenharmony_ci{
172813498266Sopenharmony_ci  CURLcode result = CURLE_OK;
172913498266Sopenharmony_ci  bool connected = FALSE;
173013498266Sopenharmony_ci
173113498266Sopenharmony_ci  /* Make sure size is unknown at this point */
173213498266Sopenharmony_ci  data->req.size = -1;
173313498266Sopenharmony_ci
173413498266Sopenharmony_ci  /* Set the progress data */
173513498266Sopenharmony_ci  Curl_pgrsSetUploadCounter(data, 0);
173613498266Sopenharmony_ci  Curl_pgrsSetDownloadCounter(data, 0);
173713498266Sopenharmony_ci  Curl_pgrsSetUploadSize(data, -1);
173813498266Sopenharmony_ci  Curl_pgrsSetDownloadSize(data, -1);
173913498266Sopenharmony_ci
174013498266Sopenharmony_ci  /* Carry out the perform */
174113498266Sopenharmony_ci  result = imap_perform(data, &connected, dophase_done);
174213498266Sopenharmony_ci
174313498266Sopenharmony_ci  /* Perform post DO phase operations if necessary */
174413498266Sopenharmony_ci  if(!result && *dophase_done)
174513498266Sopenharmony_ci    result = imap_dophase_done(data, connected);
174613498266Sopenharmony_ci
174713498266Sopenharmony_ci  return result;
174813498266Sopenharmony_ci}
174913498266Sopenharmony_ci
175013498266Sopenharmony_cistatic CURLcode imap_setup_connection(struct Curl_easy *data,
175113498266Sopenharmony_ci                                      struct connectdata *conn)
175213498266Sopenharmony_ci{
175313498266Sopenharmony_ci  /* Initialise the IMAP layer */
175413498266Sopenharmony_ci  CURLcode result = imap_init(data);
175513498266Sopenharmony_ci  if(result)
175613498266Sopenharmony_ci    return result;
175713498266Sopenharmony_ci
175813498266Sopenharmony_ci  /* Clear the TLS upgraded flag */
175913498266Sopenharmony_ci  conn->bits.tls_upgraded = FALSE;
176013498266Sopenharmony_ci
176113498266Sopenharmony_ci  return CURLE_OK;
176213498266Sopenharmony_ci}
176313498266Sopenharmony_ci
176413498266Sopenharmony_ci/***********************************************************************
176513498266Sopenharmony_ci *
176613498266Sopenharmony_ci * imap_sendf()
176713498266Sopenharmony_ci *
176813498266Sopenharmony_ci * Sends the formatted string as an IMAP command to the server.
176913498266Sopenharmony_ci *
177013498266Sopenharmony_ci * Designed to never block.
177113498266Sopenharmony_ci */
177213498266Sopenharmony_cistatic CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
177313498266Sopenharmony_ci{
177413498266Sopenharmony_ci  CURLcode result = CURLE_OK;
177513498266Sopenharmony_ci  struct imap_conn *imapc = &data->conn->proto.imapc;
177613498266Sopenharmony_ci
177713498266Sopenharmony_ci  DEBUGASSERT(fmt);
177813498266Sopenharmony_ci
177913498266Sopenharmony_ci  /* Calculate the tag based on the connection ID and command ID */
178013498266Sopenharmony_ci  msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
178113498266Sopenharmony_ci            'A' + curlx_sltosi((long)(data->conn->connection_id % 26)),
178213498266Sopenharmony_ci            ++imapc->cmdid);
178313498266Sopenharmony_ci
178413498266Sopenharmony_ci  /* start with a blank buffer */
178513498266Sopenharmony_ci  Curl_dyn_reset(&imapc->dyn);
178613498266Sopenharmony_ci
178713498266Sopenharmony_ci  /* append tag + space + fmt */
178813498266Sopenharmony_ci  result = Curl_dyn_addf(&imapc->dyn, "%s %s", imapc->resptag, fmt);
178913498266Sopenharmony_ci  if(!result) {
179013498266Sopenharmony_ci    va_list ap;
179113498266Sopenharmony_ci    va_start(ap, fmt);
179213498266Sopenharmony_ci#ifdef __clang__
179313498266Sopenharmony_ci#pragma clang diagnostic push
179413498266Sopenharmony_ci#pragma clang diagnostic ignored "-Wformat-nonliteral"
179513498266Sopenharmony_ci#endif
179613498266Sopenharmony_ci    result = Curl_pp_vsendf(data, &imapc->pp, Curl_dyn_ptr(&imapc->dyn), ap);
179713498266Sopenharmony_ci#ifdef __clang__
179813498266Sopenharmony_ci#pragma clang diagnostic pop
179913498266Sopenharmony_ci#endif
180013498266Sopenharmony_ci    va_end(ap);
180113498266Sopenharmony_ci  }
180213498266Sopenharmony_ci  return result;
180313498266Sopenharmony_ci}
180413498266Sopenharmony_ci
180513498266Sopenharmony_ci/***********************************************************************
180613498266Sopenharmony_ci *
180713498266Sopenharmony_ci * imap_atom()
180813498266Sopenharmony_ci *
180913498266Sopenharmony_ci * Checks the input string for characters that need escaping and returns an
181013498266Sopenharmony_ci * atom ready for sending to the server.
181113498266Sopenharmony_ci *
181213498266Sopenharmony_ci * The returned string needs to be freed.
181313498266Sopenharmony_ci *
181413498266Sopenharmony_ci */
181513498266Sopenharmony_cistatic char *imap_atom(const char *str, bool escape_only)
181613498266Sopenharmony_ci{
181713498266Sopenharmony_ci  struct dynbuf line;
181813498266Sopenharmony_ci  size_t nclean;
181913498266Sopenharmony_ci  size_t len;
182013498266Sopenharmony_ci
182113498266Sopenharmony_ci  if(!str)
182213498266Sopenharmony_ci    return NULL;
182313498266Sopenharmony_ci
182413498266Sopenharmony_ci  len = strlen(str);
182513498266Sopenharmony_ci  nclean = strcspn(str, "() {%*]\\\"");
182613498266Sopenharmony_ci  if(len == nclean)
182713498266Sopenharmony_ci    /* nothing to escape, return a strdup */
182813498266Sopenharmony_ci    return strdup(str);
182913498266Sopenharmony_ci
183013498266Sopenharmony_ci  Curl_dyn_init(&line, 2000);
183113498266Sopenharmony_ci
183213498266Sopenharmony_ci  if(!escape_only && Curl_dyn_addn(&line, "\"", 1))
183313498266Sopenharmony_ci    return NULL;
183413498266Sopenharmony_ci
183513498266Sopenharmony_ci  while(*str) {
183613498266Sopenharmony_ci    if((*str == '\\' || *str == '"') &&
183713498266Sopenharmony_ci       Curl_dyn_addn(&line, "\\", 1))
183813498266Sopenharmony_ci      return NULL;
183913498266Sopenharmony_ci    if(Curl_dyn_addn(&line, str, 1))
184013498266Sopenharmony_ci      return NULL;
184113498266Sopenharmony_ci    str++;
184213498266Sopenharmony_ci  }
184313498266Sopenharmony_ci
184413498266Sopenharmony_ci  if(!escape_only && Curl_dyn_addn(&line, "\"", 1))
184513498266Sopenharmony_ci    return NULL;
184613498266Sopenharmony_ci
184713498266Sopenharmony_ci  return Curl_dyn_ptr(&line);
184813498266Sopenharmony_ci}
184913498266Sopenharmony_ci
185013498266Sopenharmony_ci/***********************************************************************
185113498266Sopenharmony_ci *
185213498266Sopenharmony_ci * imap_is_bchar()
185313498266Sopenharmony_ci *
185413498266Sopenharmony_ci * Portable test of whether the specified char is a "bchar" as defined in the
185513498266Sopenharmony_ci * grammar of RFC-5092.
185613498266Sopenharmony_ci */
185713498266Sopenharmony_cistatic bool imap_is_bchar(char ch)
185813498266Sopenharmony_ci{
185913498266Sopenharmony_ci  /* Performing the alnum check with this macro is faster because of ASCII
186013498266Sopenharmony_ci     arithmetic */
186113498266Sopenharmony_ci  if(ISALNUM(ch))
186213498266Sopenharmony_ci    return true;
186313498266Sopenharmony_ci
186413498266Sopenharmony_ci  switch(ch) {
186513498266Sopenharmony_ci    /* bchar */
186613498266Sopenharmony_ci    case ':': case '@': case '/':
186713498266Sopenharmony_ci    /* bchar -> achar */
186813498266Sopenharmony_ci    case '&': case '=':
186913498266Sopenharmony_ci    /* bchar -> achar -> uchar -> unreserved (without alphanumeric) */
187013498266Sopenharmony_ci    case '-': case '.': case '_': case '~':
187113498266Sopenharmony_ci    /* bchar -> achar -> uchar -> sub-delims-sh */
187213498266Sopenharmony_ci    case '!': case '$': case '\'': case '(': case ')': case '*':
187313498266Sopenharmony_ci    case '+': case ',':
187413498266Sopenharmony_ci    /* bchar -> achar -> uchar -> pct-encoded */
187513498266Sopenharmony_ci    case '%': /* HEXDIG chars are already included above */
187613498266Sopenharmony_ci      return true;
187713498266Sopenharmony_ci
187813498266Sopenharmony_ci    default:
187913498266Sopenharmony_ci      return false;
188013498266Sopenharmony_ci  }
188113498266Sopenharmony_ci}
188213498266Sopenharmony_ci
188313498266Sopenharmony_ci/***********************************************************************
188413498266Sopenharmony_ci *
188513498266Sopenharmony_ci * imap_parse_url_options()
188613498266Sopenharmony_ci *
188713498266Sopenharmony_ci * Parse the URL login options.
188813498266Sopenharmony_ci */
188913498266Sopenharmony_cistatic CURLcode imap_parse_url_options(struct connectdata *conn)
189013498266Sopenharmony_ci{
189113498266Sopenharmony_ci  CURLcode result = CURLE_OK;
189213498266Sopenharmony_ci  struct imap_conn *imapc = &conn->proto.imapc;
189313498266Sopenharmony_ci  const char *ptr = conn->options;
189413498266Sopenharmony_ci  bool prefer_login = false;
189513498266Sopenharmony_ci
189613498266Sopenharmony_ci  while(!result && ptr && *ptr) {
189713498266Sopenharmony_ci    const char *key = ptr;
189813498266Sopenharmony_ci    const char *value;
189913498266Sopenharmony_ci
190013498266Sopenharmony_ci    while(*ptr && *ptr != '=')
190113498266Sopenharmony_ci      ptr++;
190213498266Sopenharmony_ci
190313498266Sopenharmony_ci    value = ptr + 1;
190413498266Sopenharmony_ci
190513498266Sopenharmony_ci    while(*ptr && *ptr != ';')
190613498266Sopenharmony_ci      ptr++;
190713498266Sopenharmony_ci
190813498266Sopenharmony_ci    if(strncasecompare(key, "AUTH=+LOGIN", 11)) {
190913498266Sopenharmony_ci      /* User prefers plaintext LOGIN over any SASL, including SASL LOGIN */
191013498266Sopenharmony_ci      prefer_login = true;
191113498266Sopenharmony_ci      imapc->sasl.prefmech = SASL_AUTH_NONE;
191213498266Sopenharmony_ci    }
191313498266Sopenharmony_ci    else if(strncasecompare(key, "AUTH=", 5)) {
191413498266Sopenharmony_ci      prefer_login = false;
191513498266Sopenharmony_ci      result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
191613498266Sopenharmony_ci                                               value, ptr - value);
191713498266Sopenharmony_ci    }
191813498266Sopenharmony_ci    else {
191913498266Sopenharmony_ci      prefer_login = false;
192013498266Sopenharmony_ci      result = CURLE_URL_MALFORMAT;
192113498266Sopenharmony_ci    }
192213498266Sopenharmony_ci
192313498266Sopenharmony_ci    if(*ptr == ';')
192413498266Sopenharmony_ci      ptr++;
192513498266Sopenharmony_ci  }
192613498266Sopenharmony_ci
192713498266Sopenharmony_ci  if(prefer_login)
192813498266Sopenharmony_ci    imapc->preftype = IMAP_TYPE_CLEARTEXT;
192913498266Sopenharmony_ci  else {
193013498266Sopenharmony_ci    switch(imapc->sasl.prefmech) {
193113498266Sopenharmony_ci    case SASL_AUTH_NONE:
193213498266Sopenharmony_ci      imapc->preftype = IMAP_TYPE_NONE;
193313498266Sopenharmony_ci      break;
193413498266Sopenharmony_ci    case SASL_AUTH_DEFAULT:
193513498266Sopenharmony_ci      imapc->preftype = IMAP_TYPE_ANY;
193613498266Sopenharmony_ci      break;
193713498266Sopenharmony_ci    default:
193813498266Sopenharmony_ci      imapc->preftype = IMAP_TYPE_SASL;
193913498266Sopenharmony_ci      break;
194013498266Sopenharmony_ci    }
194113498266Sopenharmony_ci  }
194213498266Sopenharmony_ci
194313498266Sopenharmony_ci  return result;
194413498266Sopenharmony_ci}
194513498266Sopenharmony_ci
194613498266Sopenharmony_ci/***********************************************************************
194713498266Sopenharmony_ci *
194813498266Sopenharmony_ci * imap_parse_url_path()
194913498266Sopenharmony_ci *
195013498266Sopenharmony_ci * Parse the URL path into separate path components.
195113498266Sopenharmony_ci *
195213498266Sopenharmony_ci */
195313498266Sopenharmony_cistatic CURLcode imap_parse_url_path(struct Curl_easy *data)
195413498266Sopenharmony_ci{
195513498266Sopenharmony_ci  /* The imap struct is already initialised in imap_connect() */
195613498266Sopenharmony_ci  CURLcode result = CURLE_OK;
195713498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
195813498266Sopenharmony_ci  const char *begin = &data->state.up.path[1]; /* skip leading slash */
195913498266Sopenharmony_ci  const char *ptr = begin;
196013498266Sopenharmony_ci
196113498266Sopenharmony_ci  /* See how much of the URL is a valid path and decode it */
196213498266Sopenharmony_ci  while(imap_is_bchar(*ptr))
196313498266Sopenharmony_ci    ptr++;
196413498266Sopenharmony_ci
196513498266Sopenharmony_ci  if(ptr != begin) {
196613498266Sopenharmony_ci    /* Remove the trailing slash if present */
196713498266Sopenharmony_ci    const char *end = ptr;
196813498266Sopenharmony_ci    if(end > begin && end[-1] == '/')
196913498266Sopenharmony_ci      end--;
197013498266Sopenharmony_ci
197113498266Sopenharmony_ci    result = Curl_urldecode(begin, end - begin, &imap->mailbox, NULL,
197213498266Sopenharmony_ci                            REJECT_CTRL);
197313498266Sopenharmony_ci    if(result)
197413498266Sopenharmony_ci      return result;
197513498266Sopenharmony_ci  }
197613498266Sopenharmony_ci  else
197713498266Sopenharmony_ci    imap->mailbox = NULL;
197813498266Sopenharmony_ci
197913498266Sopenharmony_ci  /* There can be any number of parameters in the form ";NAME=VALUE" */
198013498266Sopenharmony_ci  while(*ptr == ';') {
198113498266Sopenharmony_ci    char *name;
198213498266Sopenharmony_ci    char *value;
198313498266Sopenharmony_ci    size_t valuelen;
198413498266Sopenharmony_ci
198513498266Sopenharmony_ci    /* Find the length of the name parameter */
198613498266Sopenharmony_ci    begin = ++ptr;
198713498266Sopenharmony_ci    while(*ptr && *ptr != '=')
198813498266Sopenharmony_ci      ptr++;
198913498266Sopenharmony_ci
199013498266Sopenharmony_ci    if(!*ptr)
199113498266Sopenharmony_ci      return CURLE_URL_MALFORMAT;
199213498266Sopenharmony_ci
199313498266Sopenharmony_ci    /* Decode the name parameter */
199413498266Sopenharmony_ci    result = Curl_urldecode(begin, ptr - begin, &name, NULL,
199513498266Sopenharmony_ci                            REJECT_CTRL);
199613498266Sopenharmony_ci    if(result)
199713498266Sopenharmony_ci      return result;
199813498266Sopenharmony_ci
199913498266Sopenharmony_ci    /* Find the length of the value parameter */
200013498266Sopenharmony_ci    begin = ++ptr;
200113498266Sopenharmony_ci    while(imap_is_bchar(*ptr))
200213498266Sopenharmony_ci      ptr++;
200313498266Sopenharmony_ci
200413498266Sopenharmony_ci    /* Decode the value parameter */
200513498266Sopenharmony_ci    result = Curl_urldecode(begin, ptr - begin, &value, &valuelen,
200613498266Sopenharmony_ci                            REJECT_CTRL);
200713498266Sopenharmony_ci    if(result) {
200813498266Sopenharmony_ci      free(name);
200913498266Sopenharmony_ci      return result;
201013498266Sopenharmony_ci    }
201113498266Sopenharmony_ci
201213498266Sopenharmony_ci    DEBUGF(infof(data, "IMAP URL parameter '%s' = '%s'", name, value));
201313498266Sopenharmony_ci
201413498266Sopenharmony_ci    /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and
201513498266Sopenharmony_ci       PARTIAL) stripping of the trailing slash character if it is present.
201613498266Sopenharmony_ci
201713498266Sopenharmony_ci       Note: Unknown parameters trigger a URL_MALFORMAT error. */
201813498266Sopenharmony_ci    if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) {
201913498266Sopenharmony_ci      if(valuelen > 0 && value[valuelen - 1] == '/')
202013498266Sopenharmony_ci        value[valuelen - 1] = '\0';
202113498266Sopenharmony_ci
202213498266Sopenharmony_ci      imap->uidvalidity = value;
202313498266Sopenharmony_ci      value = NULL;
202413498266Sopenharmony_ci    }
202513498266Sopenharmony_ci    else if(strcasecompare(name, "UID") && !imap->uid) {
202613498266Sopenharmony_ci      if(valuelen > 0 && value[valuelen - 1] == '/')
202713498266Sopenharmony_ci        value[valuelen - 1] = '\0';
202813498266Sopenharmony_ci
202913498266Sopenharmony_ci      imap->uid = value;
203013498266Sopenharmony_ci      value = NULL;
203113498266Sopenharmony_ci    }
203213498266Sopenharmony_ci    else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) {
203313498266Sopenharmony_ci      if(valuelen > 0 && value[valuelen - 1] == '/')
203413498266Sopenharmony_ci        value[valuelen - 1] = '\0';
203513498266Sopenharmony_ci
203613498266Sopenharmony_ci      imap->mindex = value;
203713498266Sopenharmony_ci      value = NULL;
203813498266Sopenharmony_ci    }
203913498266Sopenharmony_ci    else if(strcasecompare(name, "SECTION") && !imap->section) {
204013498266Sopenharmony_ci      if(valuelen > 0 && value[valuelen - 1] == '/')
204113498266Sopenharmony_ci        value[valuelen - 1] = '\0';
204213498266Sopenharmony_ci
204313498266Sopenharmony_ci      imap->section = value;
204413498266Sopenharmony_ci      value = NULL;
204513498266Sopenharmony_ci    }
204613498266Sopenharmony_ci    else if(strcasecompare(name, "PARTIAL") && !imap->partial) {
204713498266Sopenharmony_ci      if(valuelen > 0 && value[valuelen - 1] == '/')
204813498266Sopenharmony_ci        value[valuelen - 1] = '\0';
204913498266Sopenharmony_ci
205013498266Sopenharmony_ci      imap->partial = value;
205113498266Sopenharmony_ci      value = NULL;
205213498266Sopenharmony_ci    }
205313498266Sopenharmony_ci    else {
205413498266Sopenharmony_ci      free(name);
205513498266Sopenharmony_ci      free(value);
205613498266Sopenharmony_ci
205713498266Sopenharmony_ci      return CURLE_URL_MALFORMAT;
205813498266Sopenharmony_ci    }
205913498266Sopenharmony_ci
206013498266Sopenharmony_ci    free(name);
206113498266Sopenharmony_ci    free(value);
206213498266Sopenharmony_ci  }
206313498266Sopenharmony_ci
206413498266Sopenharmony_ci  /* Does the URL contain a query parameter? Only valid when we have a mailbox
206513498266Sopenharmony_ci     and no UID as per RFC-5092 */
206613498266Sopenharmony_ci  if(imap->mailbox && !imap->uid && !imap->mindex) {
206713498266Sopenharmony_ci    /* Get the query parameter, URL decoded */
206813498266Sopenharmony_ci    (void)curl_url_get(data->state.uh, CURLUPART_QUERY, &imap->query,
206913498266Sopenharmony_ci                       CURLU_URLDECODE);
207013498266Sopenharmony_ci  }
207113498266Sopenharmony_ci
207213498266Sopenharmony_ci  /* Any extra stuff at the end of the URL is an error */
207313498266Sopenharmony_ci  if(*ptr)
207413498266Sopenharmony_ci    return CURLE_URL_MALFORMAT;
207513498266Sopenharmony_ci
207613498266Sopenharmony_ci  return CURLE_OK;
207713498266Sopenharmony_ci}
207813498266Sopenharmony_ci
207913498266Sopenharmony_ci/***********************************************************************
208013498266Sopenharmony_ci *
208113498266Sopenharmony_ci * imap_parse_custom_request()
208213498266Sopenharmony_ci *
208313498266Sopenharmony_ci * Parse the custom request.
208413498266Sopenharmony_ci */
208513498266Sopenharmony_cistatic CURLcode imap_parse_custom_request(struct Curl_easy *data)
208613498266Sopenharmony_ci{
208713498266Sopenharmony_ci  CURLcode result = CURLE_OK;
208813498266Sopenharmony_ci  struct IMAP *imap = data->req.p.imap;
208913498266Sopenharmony_ci  const char *custom = data->set.str[STRING_CUSTOMREQUEST];
209013498266Sopenharmony_ci
209113498266Sopenharmony_ci  if(custom) {
209213498266Sopenharmony_ci    /* URL decode the custom request */
209313498266Sopenharmony_ci    result = Curl_urldecode(custom, 0, &imap->custom, NULL, REJECT_CTRL);
209413498266Sopenharmony_ci
209513498266Sopenharmony_ci    /* Extract the parameters if specified */
209613498266Sopenharmony_ci    if(!result) {
209713498266Sopenharmony_ci      const char *params = imap->custom;
209813498266Sopenharmony_ci
209913498266Sopenharmony_ci      while(*params && *params != ' ')
210013498266Sopenharmony_ci        params++;
210113498266Sopenharmony_ci
210213498266Sopenharmony_ci      if(*params) {
210313498266Sopenharmony_ci        imap->custom_params = strdup(params);
210413498266Sopenharmony_ci        imap->custom[params - imap->custom] = '\0';
210513498266Sopenharmony_ci
210613498266Sopenharmony_ci        if(!imap->custom_params)
210713498266Sopenharmony_ci          result = CURLE_OUT_OF_MEMORY;
210813498266Sopenharmony_ci      }
210913498266Sopenharmony_ci    }
211013498266Sopenharmony_ci  }
211113498266Sopenharmony_ci
211213498266Sopenharmony_ci  return result;
211313498266Sopenharmony_ci}
211413498266Sopenharmony_ci
211513498266Sopenharmony_ci#endif /* CURL_DISABLE_IMAP */
2116