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