1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker * RFC2195 CRAM-MD5 authentication
24*6236dae4SAndroid Build Coastguard Worker * RFC2595 Using TLS with IMAP, POP3 and ACAP
25*6236dae4SAndroid Build Coastguard Worker * RFC2831 DIGEST-MD5 authentication
26*6236dae4SAndroid Build Coastguard Worker * RFC3501 IMAPv4 protocol
27*6236dae4SAndroid Build Coastguard Worker * RFC4422 Simple Authentication and Security Layer (SASL)
28*6236dae4SAndroid Build Coastguard Worker * RFC4616 PLAIN authentication
29*6236dae4SAndroid Build Coastguard Worker * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
30*6236dae4SAndroid Build Coastguard Worker * RFC4959 IMAP Extension for SASL Initial Client Response
31*6236dae4SAndroid Build Coastguard Worker * RFC5092 IMAP URL Scheme
32*6236dae4SAndroid Build Coastguard Worker * RFC6749 OAuth 2.0 Authorization Framework
33*6236dae4SAndroid Build Coastguard Worker * RFC8314 Use of TLS for Email Submission and Access
34*6236dae4SAndroid Build Coastguard Worker * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
35*6236dae4SAndroid Build Coastguard Worker *
36*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
37*6236dae4SAndroid Build Coastguard Worker
38*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
39*6236dae4SAndroid Build Coastguard Worker
40*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_IMAP
41*6236dae4SAndroid Build Coastguard Worker
42*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_IN_H
43*6236dae4SAndroid Build Coastguard Worker #include <netinet/in.h>
44*6236dae4SAndroid Build Coastguard Worker #endif
45*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_ARPA_INET_H
46*6236dae4SAndroid Build Coastguard Worker #include <arpa/inet.h>
47*6236dae4SAndroid Build Coastguard Worker #endif
48*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETDB_H
49*6236dae4SAndroid Build Coastguard Worker #include <netdb.h>
50*6236dae4SAndroid Build Coastguard Worker #endif
51*6236dae4SAndroid Build Coastguard Worker #ifdef __VMS
52*6236dae4SAndroid Build Coastguard Worker #include <in.h>
53*6236dae4SAndroid Build Coastguard Worker #include <inet.h>
54*6236dae4SAndroid Build Coastguard Worker #endif
55*6236dae4SAndroid Build Coastguard Worker
56*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
57*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
58*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
59*6236dae4SAndroid Build Coastguard Worker #include "hostip.h"
60*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
61*6236dae4SAndroid Build Coastguard Worker #include "transfer.h"
62*6236dae4SAndroid Build Coastguard Worker #include "escape.h"
63*6236dae4SAndroid Build Coastguard Worker #include "http.h" /* for HTTP proxy tunnel stuff */
64*6236dae4SAndroid Build Coastguard Worker #include "socks.h"
65*6236dae4SAndroid Build Coastguard Worker #include "imap.h"
66*6236dae4SAndroid Build Coastguard Worker #include "mime.h"
67*6236dae4SAndroid Build Coastguard Worker #include "strtoofft.h"
68*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
69*6236dae4SAndroid Build Coastguard Worker #include "vtls/vtls.h"
70*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
71*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
72*6236dae4SAndroid Build Coastguard Worker #include "select.h"
73*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
74*6236dae4SAndroid Build Coastguard Worker #include "url.h"
75*6236dae4SAndroid Build Coastguard Worker #include "bufref.h"
76*6236dae4SAndroid Build Coastguard Worker #include "curl_sasl.h"
77*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
78*6236dae4SAndroid Build Coastguard Worker #include "curl_ctype.h"
79*6236dae4SAndroid Build Coastguard Worker
80*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
81*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
82*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
83*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
84*6236dae4SAndroid Build Coastguard Worker
85*6236dae4SAndroid Build Coastguard Worker /* Local API functions */
86*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_regular_transfer(struct Curl_easy *data, bool *done);
87*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_do(struct Curl_easy *data, bool *done);
88*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
89*6236dae4SAndroid Build Coastguard Worker bool premature);
90*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_connect(struct Curl_easy *data, bool *done);
91*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_disconnect(struct Curl_easy *data,
92*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn, bool dead);
93*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done);
94*6236dae4SAndroid Build Coastguard Worker static int imap_getsock(struct Curl_easy *data, struct connectdata *conn,
95*6236dae4SAndroid Build Coastguard Worker curl_socket_t *socks);
96*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done);
97*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_setup_connection(struct Curl_easy *data,
98*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn);
99*6236dae4SAndroid Build Coastguard Worker static char *imap_atom(const char *str, bool escape_only);
100*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
101*6236dae4SAndroid Build Coastguard Worker CURL_PRINTF(2, 3);
102*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_parse_url_options(struct connectdata *conn);
103*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_parse_url_path(struct Curl_easy *data);
104*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_parse_custom_request(struct Curl_easy *data);
105*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_authenticate(struct Curl_easy *data,
106*6236dae4SAndroid Build Coastguard Worker const char *mech,
107*6236dae4SAndroid Build Coastguard Worker const struct bufref *initresp);
108*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_continue_authenticate(struct Curl_easy *data,
109*6236dae4SAndroid Build Coastguard Worker const char *mech,
110*6236dae4SAndroid Build Coastguard Worker const struct bufref *resp);
111*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_cancel_authenticate(struct Curl_easy *data,
112*6236dae4SAndroid Build Coastguard Worker const char *mech);
113*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out);
114*6236dae4SAndroid Build Coastguard Worker
115*6236dae4SAndroid Build Coastguard Worker /*
116*6236dae4SAndroid Build Coastguard Worker * IMAP protocol handler.
117*6236dae4SAndroid Build Coastguard Worker */
118*6236dae4SAndroid Build Coastguard Worker
119*6236dae4SAndroid Build Coastguard Worker const struct Curl_handler Curl_handler_imap = {
120*6236dae4SAndroid Build Coastguard Worker "imap", /* scheme */
121*6236dae4SAndroid Build Coastguard Worker imap_setup_connection, /* setup_connection */
122*6236dae4SAndroid Build Coastguard Worker imap_do, /* do_it */
123*6236dae4SAndroid Build Coastguard Worker imap_done, /* done */
124*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* do_more */
125*6236dae4SAndroid Build Coastguard Worker imap_connect, /* connect_it */
126*6236dae4SAndroid Build Coastguard Worker imap_multi_statemach, /* connecting */
127*6236dae4SAndroid Build Coastguard Worker imap_doing, /* doing */
128*6236dae4SAndroid Build Coastguard Worker imap_getsock, /* proto_getsock */
129*6236dae4SAndroid Build Coastguard Worker imap_getsock, /* doing_getsock */
130*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* domore_getsock */
131*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* perform_getsock */
132*6236dae4SAndroid Build Coastguard Worker imap_disconnect, /* disconnect */
133*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* write_resp */
134*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* write_resp_hd */
135*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* connection_check */
136*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* attach connection */
137*6236dae4SAndroid Build Coastguard Worker PORT_IMAP, /* defport */
138*6236dae4SAndroid Build Coastguard Worker CURLPROTO_IMAP, /* protocol */
139*6236dae4SAndroid Build Coastguard Worker CURLPROTO_IMAP, /* family */
140*6236dae4SAndroid Build Coastguard Worker PROTOPT_CLOSEACTION| /* flags */
141*6236dae4SAndroid Build Coastguard Worker PROTOPT_URLOPTIONS
142*6236dae4SAndroid Build Coastguard Worker };
143*6236dae4SAndroid Build Coastguard Worker
144*6236dae4SAndroid Build Coastguard Worker #ifdef USE_SSL
145*6236dae4SAndroid Build Coastguard Worker /*
146*6236dae4SAndroid Build Coastguard Worker * IMAPS protocol handler.
147*6236dae4SAndroid Build Coastguard Worker */
148*6236dae4SAndroid Build Coastguard Worker
149*6236dae4SAndroid Build Coastguard Worker const struct Curl_handler Curl_handler_imaps = {
150*6236dae4SAndroid Build Coastguard Worker "imaps", /* scheme */
151*6236dae4SAndroid Build Coastguard Worker imap_setup_connection, /* setup_connection */
152*6236dae4SAndroid Build Coastguard Worker imap_do, /* do_it */
153*6236dae4SAndroid Build Coastguard Worker imap_done, /* done */
154*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* do_more */
155*6236dae4SAndroid Build Coastguard Worker imap_connect, /* connect_it */
156*6236dae4SAndroid Build Coastguard Worker imap_multi_statemach, /* connecting */
157*6236dae4SAndroid Build Coastguard Worker imap_doing, /* doing */
158*6236dae4SAndroid Build Coastguard Worker imap_getsock, /* proto_getsock */
159*6236dae4SAndroid Build Coastguard Worker imap_getsock, /* doing_getsock */
160*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* domore_getsock */
161*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* perform_getsock */
162*6236dae4SAndroid Build Coastguard Worker imap_disconnect, /* disconnect */
163*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* write_resp */
164*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* write_resp_hd */
165*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* connection_check */
166*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* attach connection */
167*6236dae4SAndroid Build Coastguard Worker PORT_IMAPS, /* defport */
168*6236dae4SAndroid Build Coastguard Worker CURLPROTO_IMAPS, /* protocol */
169*6236dae4SAndroid Build Coastguard Worker CURLPROTO_IMAP, /* family */
170*6236dae4SAndroid Build Coastguard Worker PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
171*6236dae4SAndroid Build Coastguard Worker PROTOPT_URLOPTIONS
172*6236dae4SAndroid Build Coastguard Worker };
173*6236dae4SAndroid Build Coastguard Worker #endif
174*6236dae4SAndroid Build Coastguard Worker
175*6236dae4SAndroid Build Coastguard Worker #define IMAP_RESP_OK 1
176*6236dae4SAndroid Build Coastguard Worker #define IMAP_RESP_NOT_OK 2
177*6236dae4SAndroid Build Coastguard Worker #define IMAP_RESP_PREAUTH 3
178*6236dae4SAndroid Build Coastguard Worker
179*6236dae4SAndroid Build Coastguard Worker /* SASL parameters for the imap protocol */
180*6236dae4SAndroid Build Coastguard Worker static const struct SASLproto saslimap = {
181*6236dae4SAndroid Build Coastguard Worker "imap", /* The service name */
182*6236dae4SAndroid Build Coastguard Worker imap_perform_authenticate, /* Send authentication command */
183*6236dae4SAndroid Build Coastguard Worker imap_continue_authenticate, /* Send authentication continuation */
184*6236dae4SAndroid Build Coastguard Worker imap_cancel_authenticate, /* Send authentication cancellation */
185*6236dae4SAndroid Build Coastguard Worker imap_get_message, /* Get SASL response message */
186*6236dae4SAndroid Build Coastguard Worker 0, /* No maximum initial response length */
187*6236dae4SAndroid Build Coastguard Worker '+', /* Code received when continuation is expected */
188*6236dae4SAndroid Build Coastguard Worker IMAP_RESP_OK, /* Code to receive upon authentication success */
189*6236dae4SAndroid Build Coastguard Worker SASL_AUTH_DEFAULT, /* Default mechanisms */
190*6236dae4SAndroid Build Coastguard Worker SASL_FLAG_BASE64 /* Configuration flags */
191*6236dae4SAndroid Build Coastguard Worker };
192*6236dae4SAndroid Build Coastguard Worker
193*6236dae4SAndroid Build Coastguard Worker
194*6236dae4SAndroid Build Coastguard Worker #ifdef USE_SSL
imap_to_imaps(struct connectdata * conn)195*6236dae4SAndroid Build Coastguard Worker static void imap_to_imaps(struct connectdata *conn)
196*6236dae4SAndroid Build Coastguard Worker {
197*6236dae4SAndroid Build Coastguard Worker /* Change the connection handler */
198*6236dae4SAndroid Build Coastguard Worker conn->handler = &Curl_handler_imaps;
199*6236dae4SAndroid Build Coastguard Worker
200*6236dae4SAndroid Build Coastguard Worker /* Set the connection's upgraded to TLS flag */
201*6236dae4SAndroid Build Coastguard Worker conn->bits.tls_upgraded = TRUE;
202*6236dae4SAndroid Build Coastguard Worker }
203*6236dae4SAndroid Build Coastguard Worker #else
204*6236dae4SAndroid Build Coastguard Worker #define imap_to_imaps(x) Curl_nop_stmt
205*6236dae4SAndroid Build Coastguard Worker #endif
206*6236dae4SAndroid Build Coastguard Worker
207*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
208*6236dae4SAndroid Build Coastguard Worker *
209*6236dae4SAndroid Build Coastguard Worker * imap_matchresp()
210*6236dae4SAndroid Build Coastguard Worker *
211*6236dae4SAndroid Build Coastguard Worker * Determines whether the untagged response is related to the specified
212*6236dae4SAndroid Build Coastguard Worker * command by checking if it is in format "* <command-name> ..." or
213*6236dae4SAndroid Build Coastguard Worker * "* <number> <command-name> ...".
214*6236dae4SAndroid Build Coastguard Worker *
215*6236dae4SAndroid Build Coastguard Worker * The "* " marker is assumed to have already been checked by the caller.
216*6236dae4SAndroid Build Coastguard Worker */
imap_matchresp(const char * line,size_t len,const char * cmd)217*6236dae4SAndroid Build Coastguard Worker static bool imap_matchresp(const char *line, size_t len, const char *cmd)
218*6236dae4SAndroid Build Coastguard Worker {
219*6236dae4SAndroid Build Coastguard Worker const char *end = line + len;
220*6236dae4SAndroid Build Coastguard Worker size_t cmd_len = strlen(cmd);
221*6236dae4SAndroid Build Coastguard Worker
222*6236dae4SAndroid Build Coastguard Worker /* Skip the untagged response marker */
223*6236dae4SAndroid Build Coastguard Worker line += 2;
224*6236dae4SAndroid Build Coastguard Worker
225*6236dae4SAndroid Build Coastguard Worker /* Do we have a number after the marker? */
226*6236dae4SAndroid Build Coastguard Worker if(line < end && ISDIGIT(*line)) {
227*6236dae4SAndroid Build Coastguard Worker /* Skip the number */
228*6236dae4SAndroid Build Coastguard Worker do
229*6236dae4SAndroid Build Coastguard Worker line++;
230*6236dae4SAndroid Build Coastguard Worker while(line < end && ISDIGIT(*line));
231*6236dae4SAndroid Build Coastguard Worker
232*6236dae4SAndroid Build Coastguard Worker /* Do we have the space character? */
233*6236dae4SAndroid Build Coastguard Worker if(line == end || *line != ' ')
234*6236dae4SAndroid Build Coastguard Worker return FALSE;
235*6236dae4SAndroid Build Coastguard Worker
236*6236dae4SAndroid Build Coastguard Worker line++;
237*6236dae4SAndroid Build Coastguard Worker }
238*6236dae4SAndroid Build Coastguard Worker
239*6236dae4SAndroid Build Coastguard Worker /* Does the command name match and is it followed by a space character or at
240*6236dae4SAndroid Build Coastguard Worker the end of line? */
241*6236dae4SAndroid Build Coastguard Worker if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) &&
242*6236dae4SAndroid Build Coastguard Worker (line[cmd_len] == ' ' || line + cmd_len + 2 == end))
243*6236dae4SAndroid Build Coastguard Worker return TRUE;
244*6236dae4SAndroid Build Coastguard Worker
245*6236dae4SAndroid Build Coastguard Worker return FALSE;
246*6236dae4SAndroid Build Coastguard Worker }
247*6236dae4SAndroid Build Coastguard Worker
248*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
249*6236dae4SAndroid Build Coastguard Worker *
250*6236dae4SAndroid Build Coastguard Worker * imap_endofresp()
251*6236dae4SAndroid Build Coastguard Worker *
252*6236dae4SAndroid Build Coastguard Worker * Checks whether the given string is a valid tagged, untagged or continuation
253*6236dae4SAndroid Build Coastguard Worker * response which can be processed by the response handler.
254*6236dae4SAndroid Build Coastguard Worker */
imap_endofresp(struct Curl_easy * data,struct connectdata * conn,char * line,size_t len,int * resp)255*6236dae4SAndroid Build Coastguard Worker static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
256*6236dae4SAndroid Build Coastguard Worker char *line, size_t len, int *resp)
257*6236dae4SAndroid Build Coastguard Worker {
258*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
259*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
260*6236dae4SAndroid Build Coastguard Worker const char *id = imapc->resptag;
261*6236dae4SAndroid Build Coastguard Worker size_t id_len = strlen(id);
262*6236dae4SAndroid Build Coastguard Worker
263*6236dae4SAndroid Build Coastguard Worker /* Do we have a tagged command response? */
264*6236dae4SAndroid Build Coastguard Worker if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') {
265*6236dae4SAndroid Build Coastguard Worker line += id_len + 1;
266*6236dae4SAndroid Build Coastguard Worker len -= id_len + 1;
267*6236dae4SAndroid Build Coastguard Worker
268*6236dae4SAndroid Build Coastguard Worker if(len >= 2 && !memcmp(line, "OK", 2))
269*6236dae4SAndroid Build Coastguard Worker *resp = IMAP_RESP_OK;
270*6236dae4SAndroid Build Coastguard Worker else if(len >= 7 && !memcmp(line, "PREAUTH", 7))
271*6236dae4SAndroid Build Coastguard Worker *resp = IMAP_RESP_PREAUTH;
272*6236dae4SAndroid Build Coastguard Worker else
273*6236dae4SAndroid Build Coastguard Worker *resp = IMAP_RESP_NOT_OK;
274*6236dae4SAndroid Build Coastguard Worker
275*6236dae4SAndroid Build Coastguard Worker return TRUE;
276*6236dae4SAndroid Build Coastguard Worker }
277*6236dae4SAndroid Build Coastguard Worker
278*6236dae4SAndroid Build Coastguard Worker /* Do we have an untagged command response? */
279*6236dae4SAndroid Build Coastguard Worker if(len >= 2 && !memcmp("* ", line, 2)) {
280*6236dae4SAndroid Build Coastguard Worker switch(imapc->state) {
281*6236dae4SAndroid Build Coastguard Worker /* States which are interested in untagged responses */
282*6236dae4SAndroid Build Coastguard Worker case IMAP_CAPABILITY:
283*6236dae4SAndroid Build Coastguard Worker if(!imap_matchresp(line, len, "CAPABILITY"))
284*6236dae4SAndroid Build Coastguard Worker return FALSE;
285*6236dae4SAndroid Build Coastguard Worker break;
286*6236dae4SAndroid Build Coastguard Worker
287*6236dae4SAndroid Build Coastguard Worker case IMAP_LIST:
288*6236dae4SAndroid Build Coastguard Worker if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
289*6236dae4SAndroid Build Coastguard Worker (imap->custom && !imap_matchresp(line, len, imap->custom) &&
290*6236dae4SAndroid Build Coastguard Worker (!strcasecompare(imap->custom, "STORE") ||
291*6236dae4SAndroid Build Coastguard Worker !imap_matchresp(line, len, "FETCH")) &&
292*6236dae4SAndroid Build Coastguard Worker !strcasecompare(imap->custom, "SELECT") &&
293*6236dae4SAndroid Build Coastguard Worker !strcasecompare(imap->custom, "EXAMINE") &&
294*6236dae4SAndroid Build Coastguard Worker !strcasecompare(imap->custom, "SEARCH") &&
295*6236dae4SAndroid Build Coastguard Worker !strcasecompare(imap->custom, "EXPUNGE") &&
296*6236dae4SAndroid Build Coastguard Worker !strcasecompare(imap->custom, "LSUB") &&
297*6236dae4SAndroid Build Coastguard Worker !strcasecompare(imap->custom, "UID") &&
298*6236dae4SAndroid Build Coastguard Worker !strcasecompare(imap->custom, "GETQUOTAROOT") &&
299*6236dae4SAndroid Build Coastguard Worker !strcasecompare(imap->custom, "NOOP")))
300*6236dae4SAndroid Build Coastguard Worker return FALSE;
301*6236dae4SAndroid Build Coastguard Worker break;
302*6236dae4SAndroid Build Coastguard Worker
303*6236dae4SAndroid Build Coastguard Worker case IMAP_SELECT:
304*6236dae4SAndroid Build Coastguard Worker /* SELECT is special in that its untagged responses do not have a
305*6236dae4SAndroid Build Coastguard Worker common prefix so accept anything! */
306*6236dae4SAndroid Build Coastguard Worker break;
307*6236dae4SAndroid Build Coastguard Worker
308*6236dae4SAndroid Build Coastguard Worker case IMAP_FETCH:
309*6236dae4SAndroid Build Coastguard Worker if(!imap_matchresp(line, len, "FETCH"))
310*6236dae4SAndroid Build Coastguard Worker return FALSE;
311*6236dae4SAndroid Build Coastguard Worker break;
312*6236dae4SAndroid Build Coastguard Worker
313*6236dae4SAndroid Build Coastguard Worker case IMAP_SEARCH:
314*6236dae4SAndroid Build Coastguard Worker if(!imap_matchresp(line, len, "SEARCH"))
315*6236dae4SAndroid Build Coastguard Worker return FALSE;
316*6236dae4SAndroid Build Coastguard Worker break;
317*6236dae4SAndroid Build Coastguard Worker
318*6236dae4SAndroid Build Coastguard Worker /* Ignore other untagged responses */
319*6236dae4SAndroid Build Coastguard Worker default:
320*6236dae4SAndroid Build Coastguard Worker return FALSE;
321*6236dae4SAndroid Build Coastguard Worker }
322*6236dae4SAndroid Build Coastguard Worker
323*6236dae4SAndroid Build Coastguard Worker *resp = '*';
324*6236dae4SAndroid Build Coastguard Worker return TRUE;
325*6236dae4SAndroid Build Coastguard Worker }
326*6236dae4SAndroid Build Coastguard Worker
327*6236dae4SAndroid Build Coastguard Worker /* Do we have a continuation response? This should be a + symbol followed by
328*6236dae4SAndroid Build Coastguard Worker a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
329*6236dae4SAndroid Build Coastguard Worker APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
330*6236dae4SAndroid Build Coastguard Worker some email servers ignore this and only send a single + instead. */
331*6236dae4SAndroid Build Coastguard Worker if(imap && !imap->custom && ((len == 3 && line[0] == '+') ||
332*6236dae4SAndroid Build Coastguard Worker (len >= 2 && !memcmp("+ ", line, 2)))) {
333*6236dae4SAndroid Build Coastguard Worker switch(imapc->state) {
334*6236dae4SAndroid Build Coastguard Worker /* States which are interested in continuation responses */
335*6236dae4SAndroid Build Coastguard Worker case IMAP_AUTHENTICATE:
336*6236dae4SAndroid Build Coastguard Worker case IMAP_APPEND:
337*6236dae4SAndroid Build Coastguard Worker *resp = '+';
338*6236dae4SAndroid Build Coastguard Worker break;
339*6236dae4SAndroid Build Coastguard Worker
340*6236dae4SAndroid Build Coastguard Worker default:
341*6236dae4SAndroid Build Coastguard Worker failf(data, "Unexpected continuation response");
342*6236dae4SAndroid Build Coastguard Worker *resp = -1;
343*6236dae4SAndroid Build Coastguard Worker break;
344*6236dae4SAndroid Build Coastguard Worker }
345*6236dae4SAndroid Build Coastguard Worker
346*6236dae4SAndroid Build Coastguard Worker return TRUE;
347*6236dae4SAndroid Build Coastguard Worker }
348*6236dae4SAndroid Build Coastguard Worker
349*6236dae4SAndroid Build Coastguard Worker return FALSE; /* Nothing for us */
350*6236dae4SAndroid Build Coastguard Worker }
351*6236dae4SAndroid Build Coastguard Worker
352*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
353*6236dae4SAndroid Build Coastguard Worker *
354*6236dae4SAndroid Build Coastguard Worker * imap_get_message()
355*6236dae4SAndroid Build Coastguard Worker *
356*6236dae4SAndroid Build Coastguard Worker * Gets the authentication message from the response buffer.
357*6236dae4SAndroid Build Coastguard Worker */
imap_get_message(struct Curl_easy * data,struct bufref * out)358*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out)
359*6236dae4SAndroid Build Coastguard Worker {
360*6236dae4SAndroid Build Coastguard Worker char *message = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
361*6236dae4SAndroid Build Coastguard Worker size_t len = data->conn->proto.imapc.pp.nfinal;
362*6236dae4SAndroid Build Coastguard Worker
363*6236dae4SAndroid Build Coastguard Worker if(len > 2) {
364*6236dae4SAndroid Build Coastguard Worker /* Find the start of the message */
365*6236dae4SAndroid Build Coastguard Worker len -= 2;
366*6236dae4SAndroid Build Coastguard Worker for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
367*6236dae4SAndroid Build Coastguard Worker ;
368*6236dae4SAndroid Build Coastguard Worker
369*6236dae4SAndroid Build Coastguard Worker /* Find the end of the message */
370*6236dae4SAndroid Build Coastguard Worker while(len--)
371*6236dae4SAndroid Build Coastguard Worker if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
372*6236dae4SAndroid Build Coastguard Worker message[len] != '\t')
373*6236dae4SAndroid Build Coastguard Worker break;
374*6236dae4SAndroid Build Coastguard Worker
375*6236dae4SAndroid Build Coastguard Worker /* Terminate the message */
376*6236dae4SAndroid Build Coastguard Worker message[++len] = '\0';
377*6236dae4SAndroid Build Coastguard Worker Curl_bufref_set(out, message, len, NULL);
378*6236dae4SAndroid Build Coastguard Worker }
379*6236dae4SAndroid Build Coastguard Worker else
380*6236dae4SAndroid Build Coastguard Worker /* junk input => zero length output */
381*6236dae4SAndroid Build Coastguard Worker Curl_bufref_set(out, "", 0, NULL);
382*6236dae4SAndroid Build Coastguard Worker
383*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
384*6236dae4SAndroid Build Coastguard Worker }
385*6236dae4SAndroid Build Coastguard Worker
386*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
387*6236dae4SAndroid Build Coastguard Worker *
388*6236dae4SAndroid Build Coastguard Worker * imap_state()
389*6236dae4SAndroid Build Coastguard Worker *
390*6236dae4SAndroid Build Coastguard Worker * This is the ONLY way to change IMAP state!
391*6236dae4SAndroid Build Coastguard Worker */
imap_state(struct Curl_easy * data,imapstate newstate)392*6236dae4SAndroid Build Coastguard Worker static void imap_state(struct Curl_easy *data, imapstate newstate)
393*6236dae4SAndroid Build Coastguard Worker {
394*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &data->conn->proto.imapc;
395*6236dae4SAndroid Build Coastguard Worker #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
396*6236dae4SAndroid Build Coastguard Worker /* for debug purposes */
397*6236dae4SAndroid Build Coastguard Worker static const char * const names[]={
398*6236dae4SAndroid Build Coastguard Worker "STOP",
399*6236dae4SAndroid Build Coastguard Worker "SERVERGREET",
400*6236dae4SAndroid Build Coastguard Worker "CAPABILITY",
401*6236dae4SAndroid Build Coastguard Worker "STARTTLS",
402*6236dae4SAndroid Build Coastguard Worker "UPGRADETLS",
403*6236dae4SAndroid Build Coastguard Worker "AUTHENTICATE",
404*6236dae4SAndroid Build Coastguard Worker "LOGIN",
405*6236dae4SAndroid Build Coastguard Worker "LIST",
406*6236dae4SAndroid Build Coastguard Worker "SELECT",
407*6236dae4SAndroid Build Coastguard Worker "FETCH",
408*6236dae4SAndroid Build Coastguard Worker "FETCH_FINAL",
409*6236dae4SAndroid Build Coastguard Worker "APPEND",
410*6236dae4SAndroid Build Coastguard Worker "APPEND_FINAL",
411*6236dae4SAndroid Build Coastguard Worker "SEARCH",
412*6236dae4SAndroid Build Coastguard Worker "LOGOUT",
413*6236dae4SAndroid Build Coastguard Worker /* LAST */
414*6236dae4SAndroid Build Coastguard Worker };
415*6236dae4SAndroid Build Coastguard Worker
416*6236dae4SAndroid Build Coastguard Worker if(imapc->state != newstate)
417*6236dae4SAndroid Build Coastguard Worker infof(data, "IMAP %p state change from %s to %s",
418*6236dae4SAndroid Build Coastguard Worker (void *)imapc, names[imapc->state], names[newstate]);
419*6236dae4SAndroid Build Coastguard Worker #endif
420*6236dae4SAndroid Build Coastguard Worker
421*6236dae4SAndroid Build Coastguard Worker imapc->state = newstate;
422*6236dae4SAndroid Build Coastguard Worker }
423*6236dae4SAndroid Build Coastguard Worker
424*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
425*6236dae4SAndroid Build Coastguard Worker *
426*6236dae4SAndroid Build Coastguard Worker * imap_perform_capability()
427*6236dae4SAndroid Build Coastguard Worker *
428*6236dae4SAndroid Build Coastguard Worker * Sends the CAPABILITY command in order to obtain a list of server side
429*6236dae4SAndroid Build Coastguard Worker * supported capabilities.
430*6236dae4SAndroid Build Coastguard Worker */
imap_perform_capability(struct Curl_easy * data,struct connectdata * conn)431*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_capability(struct Curl_easy *data,
432*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
433*6236dae4SAndroid Build Coastguard Worker {
434*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
435*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
436*6236dae4SAndroid Build Coastguard Worker imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
437*6236dae4SAndroid Build Coastguard Worker imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */
438*6236dae4SAndroid Build Coastguard Worker imapc->tls_supported = FALSE; /* Clear the TLS capability */
439*6236dae4SAndroid Build Coastguard Worker
440*6236dae4SAndroid Build Coastguard Worker /* Send the CAPABILITY command */
441*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "CAPABILITY");
442*6236dae4SAndroid Build Coastguard Worker
443*6236dae4SAndroid Build Coastguard Worker if(!result)
444*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_CAPABILITY);
445*6236dae4SAndroid Build Coastguard Worker
446*6236dae4SAndroid Build Coastguard Worker return result;
447*6236dae4SAndroid Build Coastguard Worker }
448*6236dae4SAndroid Build Coastguard Worker
449*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
450*6236dae4SAndroid Build Coastguard Worker *
451*6236dae4SAndroid Build Coastguard Worker * imap_perform_starttls()
452*6236dae4SAndroid Build Coastguard Worker *
453*6236dae4SAndroid Build Coastguard Worker * Sends the STARTTLS command to start the upgrade to TLS.
454*6236dae4SAndroid Build Coastguard Worker */
imap_perform_starttls(struct Curl_easy * data)455*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_starttls(struct Curl_easy *data)
456*6236dae4SAndroid Build Coastguard Worker {
457*6236dae4SAndroid Build Coastguard Worker /* Send the STARTTLS command */
458*6236dae4SAndroid Build Coastguard Worker CURLcode result = imap_sendf(data, "STARTTLS");
459*6236dae4SAndroid Build Coastguard Worker
460*6236dae4SAndroid Build Coastguard Worker if(!result)
461*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STARTTLS);
462*6236dae4SAndroid Build Coastguard Worker
463*6236dae4SAndroid Build Coastguard Worker return result;
464*6236dae4SAndroid Build Coastguard Worker }
465*6236dae4SAndroid Build Coastguard Worker
466*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
467*6236dae4SAndroid Build Coastguard Worker *
468*6236dae4SAndroid Build Coastguard Worker * imap_perform_upgrade_tls()
469*6236dae4SAndroid Build Coastguard Worker *
470*6236dae4SAndroid Build Coastguard Worker * Performs the upgrade to TLS.
471*6236dae4SAndroid Build Coastguard Worker */
imap_perform_upgrade_tls(struct Curl_easy * data,struct connectdata * conn)472*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
473*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
474*6236dae4SAndroid Build Coastguard Worker {
475*6236dae4SAndroid Build Coastguard Worker /* Start the SSL connection */
476*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
477*6236dae4SAndroid Build Coastguard Worker CURLcode result;
478*6236dae4SAndroid Build Coastguard Worker bool ssldone = FALSE;
479*6236dae4SAndroid Build Coastguard Worker
480*6236dae4SAndroid Build Coastguard Worker if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
481*6236dae4SAndroid Build Coastguard Worker result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
482*6236dae4SAndroid Build Coastguard Worker if(result)
483*6236dae4SAndroid Build Coastguard Worker goto out;
484*6236dae4SAndroid Build Coastguard Worker }
485*6236dae4SAndroid Build Coastguard Worker
486*6236dae4SAndroid Build Coastguard Worker result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
487*6236dae4SAndroid Build Coastguard Worker if(!result) {
488*6236dae4SAndroid Build Coastguard Worker imapc->ssldone = ssldone;
489*6236dae4SAndroid Build Coastguard Worker if(imapc->state != IMAP_UPGRADETLS)
490*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_UPGRADETLS);
491*6236dae4SAndroid Build Coastguard Worker
492*6236dae4SAndroid Build Coastguard Worker if(imapc->ssldone) {
493*6236dae4SAndroid Build Coastguard Worker imap_to_imaps(conn);
494*6236dae4SAndroid Build Coastguard Worker result = imap_perform_capability(data, conn);
495*6236dae4SAndroid Build Coastguard Worker }
496*6236dae4SAndroid Build Coastguard Worker }
497*6236dae4SAndroid Build Coastguard Worker out:
498*6236dae4SAndroid Build Coastguard Worker return result;
499*6236dae4SAndroid Build Coastguard Worker }
500*6236dae4SAndroid Build Coastguard Worker
501*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
502*6236dae4SAndroid Build Coastguard Worker *
503*6236dae4SAndroid Build Coastguard Worker * imap_perform_login()
504*6236dae4SAndroid Build Coastguard Worker *
505*6236dae4SAndroid Build Coastguard Worker * Sends a clear text LOGIN command to authenticate with.
506*6236dae4SAndroid Build Coastguard Worker */
imap_perform_login(struct Curl_easy * data,struct connectdata * conn)507*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_login(struct Curl_easy *data,
508*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
509*6236dae4SAndroid Build Coastguard Worker {
510*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
511*6236dae4SAndroid Build Coastguard Worker char *user;
512*6236dae4SAndroid Build Coastguard Worker char *passwd;
513*6236dae4SAndroid Build Coastguard Worker
514*6236dae4SAndroid Build Coastguard Worker /* Check we have a username and password to authenticate with and end the
515*6236dae4SAndroid Build Coastguard Worker connect phase if we do not */
516*6236dae4SAndroid Build Coastguard Worker if(!data->state.aptr.user) {
517*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
518*6236dae4SAndroid Build Coastguard Worker
519*6236dae4SAndroid Build Coastguard Worker return result;
520*6236dae4SAndroid Build Coastguard Worker }
521*6236dae4SAndroid Build Coastguard Worker
522*6236dae4SAndroid Build Coastguard Worker /* Make sure the username and password are in the correct atom format */
523*6236dae4SAndroid Build Coastguard Worker user = imap_atom(conn->user, FALSE);
524*6236dae4SAndroid Build Coastguard Worker passwd = imap_atom(conn->passwd, FALSE);
525*6236dae4SAndroid Build Coastguard Worker
526*6236dae4SAndroid Build Coastguard Worker /* Send the LOGIN command */
527*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "LOGIN %s %s", user ? user : "",
528*6236dae4SAndroid Build Coastguard Worker passwd ? passwd : "");
529*6236dae4SAndroid Build Coastguard Worker
530*6236dae4SAndroid Build Coastguard Worker free(user);
531*6236dae4SAndroid Build Coastguard Worker free(passwd);
532*6236dae4SAndroid Build Coastguard Worker
533*6236dae4SAndroid Build Coastguard Worker if(!result)
534*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_LOGIN);
535*6236dae4SAndroid Build Coastguard Worker
536*6236dae4SAndroid Build Coastguard Worker return result;
537*6236dae4SAndroid Build Coastguard Worker }
538*6236dae4SAndroid Build Coastguard Worker
539*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
540*6236dae4SAndroid Build Coastguard Worker *
541*6236dae4SAndroid Build Coastguard Worker * imap_perform_authenticate()
542*6236dae4SAndroid Build Coastguard Worker *
543*6236dae4SAndroid Build Coastguard Worker * Sends an AUTHENTICATE command allowing the client to login with the given
544*6236dae4SAndroid Build Coastguard Worker * SASL authentication mechanism.
545*6236dae4SAndroid Build Coastguard Worker */
imap_perform_authenticate(struct Curl_easy * data,const char * mech,const struct bufref * initresp)546*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_authenticate(struct Curl_easy *data,
547*6236dae4SAndroid Build Coastguard Worker const char *mech,
548*6236dae4SAndroid Build Coastguard Worker const struct bufref *initresp)
549*6236dae4SAndroid Build Coastguard Worker {
550*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
551*6236dae4SAndroid Build Coastguard Worker const char *ir = (const char *) Curl_bufref_ptr(initresp);
552*6236dae4SAndroid Build Coastguard Worker
553*6236dae4SAndroid Build Coastguard Worker if(ir) {
554*6236dae4SAndroid Build Coastguard Worker /* Send the AUTHENTICATE command with the initial response */
555*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "AUTHENTICATE %s %s", mech, ir);
556*6236dae4SAndroid Build Coastguard Worker }
557*6236dae4SAndroid Build Coastguard Worker else {
558*6236dae4SAndroid Build Coastguard Worker /* Send the AUTHENTICATE command */
559*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "AUTHENTICATE %s", mech);
560*6236dae4SAndroid Build Coastguard Worker }
561*6236dae4SAndroid Build Coastguard Worker
562*6236dae4SAndroid Build Coastguard Worker return result;
563*6236dae4SAndroid Build Coastguard Worker }
564*6236dae4SAndroid Build Coastguard Worker
565*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
566*6236dae4SAndroid Build Coastguard Worker *
567*6236dae4SAndroid Build Coastguard Worker * imap_continue_authenticate()
568*6236dae4SAndroid Build Coastguard Worker *
569*6236dae4SAndroid Build Coastguard Worker * Sends SASL continuation data.
570*6236dae4SAndroid Build Coastguard Worker */
imap_continue_authenticate(struct Curl_easy * data,const char * mech,const struct bufref * resp)571*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_continue_authenticate(struct Curl_easy *data,
572*6236dae4SAndroid Build Coastguard Worker const char *mech,
573*6236dae4SAndroid Build Coastguard Worker const struct bufref *resp)
574*6236dae4SAndroid Build Coastguard Worker {
575*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &data->conn->proto.imapc;
576*6236dae4SAndroid Build Coastguard Worker
577*6236dae4SAndroid Build Coastguard Worker (void)mech;
578*6236dae4SAndroid Build Coastguard Worker
579*6236dae4SAndroid Build Coastguard Worker return Curl_pp_sendf(data, &imapc->pp,
580*6236dae4SAndroid Build Coastguard Worker "%s", (const char *) Curl_bufref_ptr(resp));
581*6236dae4SAndroid Build Coastguard Worker }
582*6236dae4SAndroid Build Coastguard Worker
583*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
584*6236dae4SAndroid Build Coastguard Worker *
585*6236dae4SAndroid Build Coastguard Worker * imap_cancel_authenticate()
586*6236dae4SAndroid Build Coastguard Worker *
587*6236dae4SAndroid Build Coastguard Worker * Sends SASL cancellation.
588*6236dae4SAndroid Build Coastguard Worker */
imap_cancel_authenticate(struct Curl_easy * data,const char * mech)589*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_cancel_authenticate(struct Curl_easy *data,
590*6236dae4SAndroid Build Coastguard Worker const char *mech)
591*6236dae4SAndroid Build Coastguard Worker {
592*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &data->conn->proto.imapc;
593*6236dae4SAndroid Build Coastguard Worker
594*6236dae4SAndroid Build Coastguard Worker (void)mech;
595*6236dae4SAndroid Build Coastguard Worker
596*6236dae4SAndroid Build Coastguard Worker return Curl_pp_sendf(data, &imapc->pp, "*");
597*6236dae4SAndroid Build Coastguard Worker }
598*6236dae4SAndroid Build Coastguard Worker
599*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
600*6236dae4SAndroid Build Coastguard Worker *
601*6236dae4SAndroid Build Coastguard Worker * imap_perform_authentication()
602*6236dae4SAndroid Build Coastguard Worker *
603*6236dae4SAndroid Build Coastguard Worker * Initiates the authentication sequence, with the appropriate SASL
604*6236dae4SAndroid Build Coastguard Worker * authentication mechanism, falling back to clear text should a common
605*6236dae4SAndroid Build Coastguard Worker * mechanism not be available between the client and server.
606*6236dae4SAndroid Build Coastguard Worker */
imap_perform_authentication(struct Curl_easy * data,struct connectdata * conn)607*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_authentication(struct Curl_easy *data,
608*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
609*6236dae4SAndroid Build Coastguard Worker {
610*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
611*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
612*6236dae4SAndroid Build Coastguard Worker saslprogress progress;
613*6236dae4SAndroid Build Coastguard Worker
614*6236dae4SAndroid Build Coastguard Worker /* Check if already authenticated OR if there is enough data to authenticate
615*6236dae4SAndroid Build Coastguard Worker with and end the connect phase if we do not */
616*6236dae4SAndroid Build Coastguard Worker if(imapc->preauth ||
617*6236dae4SAndroid Build Coastguard Worker !Curl_sasl_can_authenticate(&imapc->sasl, data)) {
618*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
619*6236dae4SAndroid Build Coastguard Worker return result;
620*6236dae4SAndroid Build Coastguard Worker }
621*6236dae4SAndroid Build Coastguard Worker
622*6236dae4SAndroid Build Coastguard Worker /* Calculate the SASL login details */
623*6236dae4SAndroid Build Coastguard Worker result = Curl_sasl_start(&imapc->sasl, data, imapc->ir_supported, &progress);
624*6236dae4SAndroid Build Coastguard Worker
625*6236dae4SAndroid Build Coastguard Worker if(!result) {
626*6236dae4SAndroid Build Coastguard Worker if(progress == SASL_INPROGRESS)
627*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_AUTHENTICATE);
628*6236dae4SAndroid Build Coastguard Worker else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
629*6236dae4SAndroid Build Coastguard Worker /* Perform clear text authentication */
630*6236dae4SAndroid Build Coastguard Worker result = imap_perform_login(data, conn);
631*6236dae4SAndroid Build Coastguard Worker else {
632*6236dae4SAndroid Build Coastguard Worker /* Other mechanisms not supported */
633*6236dae4SAndroid Build Coastguard Worker infof(data, "No known authentication mechanisms supported");
634*6236dae4SAndroid Build Coastguard Worker result = CURLE_LOGIN_DENIED;
635*6236dae4SAndroid Build Coastguard Worker }
636*6236dae4SAndroid Build Coastguard Worker }
637*6236dae4SAndroid Build Coastguard Worker
638*6236dae4SAndroid Build Coastguard Worker return result;
639*6236dae4SAndroid Build Coastguard Worker }
640*6236dae4SAndroid Build Coastguard Worker
641*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
642*6236dae4SAndroid Build Coastguard Worker *
643*6236dae4SAndroid Build Coastguard Worker * imap_perform_list()
644*6236dae4SAndroid Build Coastguard Worker *
645*6236dae4SAndroid Build Coastguard Worker * Sends a LIST command or an alternative custom request.
646*6236dae4SAndroid Build Coastguard Worker */
imap_perform_list(struct Curl_easy * data)647*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_list(struct Curl_easy *data)
648*6236dae4SAndroid Build Coastguard Worker {
649*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
650*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
651*6236dae4SAndroid Build Coastguard Worker
652*6236dae4SAndroid Build Coastguard Worker if(imap->custom)
653*6236dae4SAndroid Build Coastguard Worker /* Send the custom request */
654*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "%s%s", imap->custom,
655*6236dae4SAndroid Build Coastguard Worker imap->custom_params ? imap->custom_params : "");
656*6236dae4SAndroid Build Coastguard Worker else {
657*6236dae4SAndroid Build Coastguard Worker /* Make sure the mailbox is in the correct atom format if necessary */
658*6236dae4SAndroid Build Coastguard Worker char *mailbox = imap->mailbox ? imap_atom(imap->mailbox, TRUE)
659*6236dae4SAndroid Build Coastguard Worker : strdup("");
660*6236dae4SAndroid Build Coastguard Worker if(!mailbox)
661*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
662*6236dae4SAndroid Build Coastguard Worker
663*6236dae4SAndroid Build Coastguard Worker /* Send the LIST command */
664*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "LIST \"%s\" *", mailbox);
665*6236dae4SAndroid Build Coastguard Worker
666*6236dae4SAndroid Build Coastguard Worker free(mailbox);
667*6236dae4SAndroid Build Coastguard Worker }
668*6236dae4SAndroid Build Coastguard Worker
669*6236dae4SAndroid Build Coastguard Worker if(!result)
670*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_LIST);
671*6236dae4SAndroid Build Coastguard Worker
672*6236dae4SAndroid Build Coastguard Worker return result;
673*6236dae4SAndroid Build Coastguard Worker }
674*6236dae4SAndroid Build Coastguard Worker
675*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
676*6236dae4SAndroid Build Coastguard Worker *
677*6236dae4SAndroid Build Coastguard Worker * imap_perform_select()
678*6236dae4SAndroid Build Coastguard Worker *
679*6236dae4SAndroid Build Coastguard Worker * Sends a SELECT command to ask the server to change the selected mailbox.
680*6236dae4SAndroid Build Coastguard Worker */
imap_perform_select(struct Curl_easy * data)681*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_select(struct Curl_easy *data)
682*6236dae4SAndroid Build Coastguard Worker {
683*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
684*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
685*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
686*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
687*6236dae4SAndroid Build Coastguard Worker char *mailbox;
688*6236dae4SAndroid Build Coastguard Worker
689*6236dae4SAndroid Build Coastguard Worker /* Invalidate old information as we are switching mailboxes */
690*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imapc->mailbox);
691*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imapc->mailbox_uidvalidity);
692*6236dae4SAndroid Build Coastguard Worker
693*6236dae4SAndroid Build Coastguard Worker /* Check we have a mailbox */
694*6236dae4SAndroid Build Coastguard Worker if(!imap->mailbox) {
695*6236dae4SAndroid Build Coastguard Worker failf(data, "Cannot SELECT without a mailbox.");
696*6236dae4SAndroid Build Coastguard Worker return CURLE_URL_MALFORMAT;
697*6236dae4SAndroid Build Coastguard Worker }
698*6236dae4SAndroid Build Coastguard Worker
699*6236dae4SAndroid Build Coastguard Worker /* Make sure the mailbox is in the correct atom format */
700*6236dae4SAndroid Build Coastguard Worker mailbox = imap_atom(imap->mailbox, FALSE);
701*6236dae4SAndroid Build Coastguard Worker if(!mailbox)
702*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
703*6236dae4SAndroid Build Coastguard Worker
704*6236dae4SAndroid Build Coastguard Worker /* Send the SELECT command */
705*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "SELECT %s", mailbox);
706*6236dae4SAndroid Build Coastguard Worker
707*6236dae4SAndroid Build Coastguard Worker free(mailbox);
708*6236dae4SAndroid Build Coastguard Worker
709*6236dae4SAndroid Build Coastguard Worker if(!result)
710*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_SELECT);
711*6236dae4SAndroid Build Coastguard Worker
712*6236dae4SAndroid Build Coastguard Worker return result;
713*6236dae4SAndroid Build Coastguard Worker }
714*6236dae4SAndroid Build Coastguard Worker
715*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
716*6236dae4SAndroid Build Coastguard Worker *
717*6236dae4SAndroid Build Coastguard Worker * imap_perform_fetch()
718*6236dae4SAndroid Build Coastguard Worker *
719*6236dae4SAndroid Build Coastguard Worker * Sends a FETCH command to initiate the download of a message.
720*6236dae4SAndroid Build Coastguard Worker */
imap_perform_fetch(struct Curl_easy * data)721*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_fetch(struct Curl_easy *data)
722*6236dae4SAndroid Build Coastguard Worker {
723*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
724*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
725*6236dae4SAndroid Build Coastguard Worker /* Check we have a UID */
726*6236dae4SAndroid Build Coastguard Worker if(imap->uid) {
727*6236dae4SAndroid Build Coastguard Worker
728*6236dae4SAndroid Build Coastguard Worker /* Send the FETCH command */
729*6236dae4SAndroid Build Coastguard Worker if(imap->partial)
730*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "UID FETCH %s BODY[%s]<%s>",
731*6236dae4SAndroid Build Coastguard Worker imap->uid, imap->section ? imap->section : "",
732*6236dae4SAndroid Build Coastguard Worker imap->partial);
733*6236dae4SAndroid Build Coastguard Worker else
734*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "UID FETCH %s BODY[%s]",
735*6236dae4SAndroid Build Coastguard Worker imap->uid, imap->section ? imap->section : "");
736*6236dae4SAndroid Build Coastguard Worker }
737*6236dae4SAndroid Build Coastguard Worker else if(imap->mindex) {
738*6236dae4SAndroid Build Coastguard Worker /* Send the FETCH command */
739*6236dae4SAndroid Build Coastguard Worker if(imap->partial)
740*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "FETCH %s BODY[%s]<%s>",
741*6236dae4SAndroid Build Coastguard Worker imap->mindex, imap->section ? imap->section : "",
742*6236dae4SAndroid Build Coastguard Worker imap->partial);
743*6236dae4SAndroid Build Coastguard Worker else
744*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "FETCH %s BODY[%s]",
745*6236dae4SAndroid Build Coastguard Worker imap->mindex, imap->section ? imap->section : "");
746*6236dae4SAndroid Build Coastguard Worker }
747*6236dae4SAndroid Build Coastguard Worker else {
748*6236dae4SAndroid Build Coastguard Worker failf(data, "Cannot FETCH without a UID.");
749*6236dae4SAndroid Build Coastguard Worker return CURLE_URL_MALFORMAT;
750*6236dae4SAndroid Build Coastguard Worker }
751*6236dae4SAndroid Build Coastguard Worker if(!result)
752*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_FETCH);
753*6236dae4SAndroid Build Coastguard Worker
754*6236dae4SAndroid Build Coastguard Worker return result;
755*6236dae4SAndroid Build Coastguard Worker }
756*6236dae4SAndroid Build Coastguard Worker
757*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
758*6236dae4SAndroid Build Coastguard Worker *
759*6236dae4SAndroid Build Coastguard Worker * imap_perform_append()
760*6236dae4SAndroid Build Coastguard Worker *
761*6236dae4SAndroid Build Coastguard Worker * Sends an APPEND command to initiate the upload of a message.
762*6236dae4SAndroid Build Coastguard Worker */
imap_perform_append(struct Curl_easy * data)763*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_append(struct Curl_easy *data)
764*6236dae4SAndroid Build Coastguard Worker {
765*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
766*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
767*6236dae4SAndroid Build Coastguard Worker char *mailbox;
768*6236dae4SAndroid Build Coastguard Worker
769*6236dae4SAndroid Build Coastguard Worker /* Check we have a mailbox */
770*6236dae4SAndroid Build Coastguard Worker if(!imap->mailbox) {
771*6236dae4SAndroid Build Coastguard Worker failf(data, "Cannot APPEND without a mailbox.");
772*6236dae4SAndroid Build Coastguard Worker return CURLE_URL_MALFORMAT;
773*6236dae4SAndroid Build Coastguard Worker }
774*6236dae4SAndroid Build Coastguard Worker
775*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_MIME
776*6236dae4SAndroid Build Coastguard Worker /* Prepare the mime data if some. */
777*6236dae4SAndroid Build Coastguard Worker if(data->set.mimepost.kind != MIMEKIND_NONE) {
778*6236dae4SAndroid Build Coastguard Worker /* Use the whole structure as data. */
779*6236dae4SAndroid Build Coastguard Worker data->set.mimepost.flags &= ~(unsigned int)MIME_BODY_ONLY;
780*6236dae4SAndroid Build Coastguard Worker
781*6236dae4SAndroid Build Coastguard Worker /* Add external headers and mime version. */
782*6236dae4SAndroid Build Coastguard Worker curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
783*6236dae4SAndroid Build Coastguard Worker result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
784*6236dae4SAndroid Build Coastguard Worker NULL, MIMESTRATEGY_MAIL);
785*6236dae4SAndroid Build Coastguard Worker
786*6236dae4SAndroid Build Coastguard Worker if(!result)
787*6236dae4SAndroid Build Coastguard Worker if(!Curl_checkheaders(data, STRCONST("Mime-Version")))
788*6236dae4SAndroid Build Coastguard Worker result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
789*6236dae4SAndroid Build Coastguard Worker "Mime-Version: 1.0");
790*6236dae4SAndroid Build Coastguard Worker
791*6236dae4SAndroid Build Coastguard Worker if(!result)
792*6236dae4SAndroid Build Coastguard Worker result = Curl_creader_set_mime(data, &data->set.mimepost);
793*6236dae4SAndroid Build Coastguard Worker if(result)
794*6236dae4SAndroid Build Coastguard Worker return result;
795*6236dae4SAndroid Build Coastguard Worker data->state.infilesize = Curl_creader_client_length(data);
796*6236dae4SAndroid Build Coastguard Worker }
797*6236dae4SAndroid Build Coastguard Worker else
798*6236dae4SAndroid Build Coastguard Worker #endif
799*6236dae4SAndroid Build Coastguard Worker {
800*6236dae4SAndroid Build Coastguard Worker result = Curl_creader_set_fread(data, data->state.infilesize);
801*6236dae4SAndroid Build Coastguard Worker if(result)
802*6236dae4SAndroid Build Coastguard Worker return result;
803*6236dae4SAndroid Build Coastguard Worker }
804*6236dae4SAndroid Build Coastguard Worker
805*6236dae4SAndroid Build Coastguard Worker /* Check we know the size of the upload */
806*6236dae4SAndroid Build Coastguard Worker if(data->state.infilesize < 0) {
807*6236dae4SAndroid Build Coastguard Worker failf(data, "Cannot APPEND with unknown input file size");
808*6236dae4SAndroid Build Coastguard Worker return CURLE_UPLOAD_FAILED;
809*6236dae4SAndroid Build Coastguard Worker }
810*6236dae4SAndroid Build Coastguard Worker
811*6236dae4SAndroid Build Coastguard Worker /* Make sure the mailbox is in the correct atom format */
812*6236dae4SAndroid Build Coastguard Worker mailbox = imap_atom(imap->mailbox, FALSE);
813*6236dae4SAndroid Build Coastguard Worker if(!mailbox)
814*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
815*6236dae4SAndroid Build Coastguard Worker
816*6236dae4SAndroid Build Coastguard Worker /* Send the APPEND command */
817*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "APPEND %s (\\Seen) {%" FMT_OFF_T "}",
818*6236dae4SAndroid Build Coastguard Worker mailbox, data->state.infilesize);
819*6236dae4SAndroid Build Coastguard Worker
820*6236dae4SAndroid Build Coastguard Worker free(mailbox);
821*6236dae4SAndroid Build Coastguard Worker
822*6236dae4SAndroid Build Coastguard Worker if(!result)
823*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_APPEND);
824*6236dae4SAndroid Build Coastguard Worker
825*6236dae4SAndroid Build Coastguard Worker return result;
826*6236dae4SAndroid Build Coastguard Worker }
827*6236dae4SAndroid Build Coastguard Worker
828*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
829*6236dae4SAndroid Build Coastguard Worker *
830*6236dae4SAndroid Build Coastguard Worker * imap_perform_search()
831*6236dae4SAndroid Build Coastguard Worker *
832*6236dae4SAndroid Build Coastguard Worker * Sends a SEARCH command.
833*6236dae4SAndroid Build Coastguard Worker */
imap_perform_search(struct Curl_easy * data)834*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_search(struct Curl_easy *data)
835*6236dae4SAndroid Build Coastguard Worker {
836*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
837*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
838*6236dae4SAndroid Build Coastguard Worker
839*6236dae4SAndroid Build Coastguard Worker /* Check we have a query string */
840*6236dae4SAndroid Build Coastguard Worker if(!imap->query) {
841*6236dae4SAndroid Build Coastguard Worker failf(data, "Cannot SEARCH without a query string.");
842*6236dae4SAndroid Build Coastguard Worker return CURLE_URL_MALFORMAT;
843*6236dae4SAndroid Build Coastguard Worker }
844*6236dae4SAndroid Build Coastguard Worker
845*6236dae4SAndroid Build Coastguard Worker /* Send the SEARCH command */
846*6236dae4SAndroid Build Coastguard Worker result = imap_sendf(data, "SEARCH %s", imap->query);
847*6236dae4SAndroid Build Coastguard Worker
848*6236dae4SAndroid Build Coastguard Worker if(!result)
849*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_SEARCH);
850*6236dae4SAndroid Build Coastguard Worker
851*6236dae4SAndroid Build Coastguard Worker return result;
852*6236dae4SAndroid Build Coastguard Worker }
853*6236dae4SAndroid Build Coastguard Worker
854*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
855*6236dae4SAndroid Build Coastguard Worker *
856*6236dae4SAndroid Build Coastguard Worker * imap_perform_logout()
857*6236dae4SAndroid Build Coastguard Worker *
858*6236dae4SAndroid Build Coastguard Worker * Performs the logout action prior to sclose() being called.
859*6236dae4SAndroid Build Coastguard Worker */
imap_perform_logout(struct Curl_easy * data)860*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform_logout(struct Curl_easy *data)
861*6236dae4SAndroid Build Coastguard Worker {
862*6236dae4SAndroid Build Coastguard Worker /* Send the LOGOUT command */
863*6236dae4SAndroid Build Coastguard Worker CURLcode result = imap_sendf(data, "LOGOUT");
864*6236dae4SAndroid Build Coastguard Worker
865*6236dae4SAndroid Build Coastguard Worker if(!result)
866*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_LOGOUT);
867*6236dae4SAndroid Build Coastguard Worker
868*6236dae4SAndroid Build Coastguard Worker return result;
869*6236dae4SAndroid Build Coastguard Worker }
870*6236dae4SAndroid Build Coastguard Worker
871*6236dae4SAndroid Build Coastguard Worker /* For the initial server greeting */
imap_state_servergreet_resp(struct Curl_easy * data,int imapcode,imapstate instate)872*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_servergreet_resp(struct Curl_easy *data,
873*6236dae4SAndroid Build Coastguard Worker int imapcode,
874*6236dae4SAndroid Build Coastguard Worker imapstate instate)
875*6236dae4SAndroid Build Coastguard Worker {
876*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
877*6236dae4SAndroid Build Coastguard Worker (void)instate; /* no use for this yet */
878*6236dae4SAndroid Build Coastguard Worker
879*6236dae4SAndroid Build Coastguard Worker if(imapcode == IMAP_RESP_PREAUTH) {
880*6236dae4SAndroid Build Coastguard Worker /* PREAUTH */
881*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
882*6236dae4SAndroid Build Coastguard Worker imapc->preauth = TRUE;
883*6236dae4SAndroid Build Coastguard Worker infof(data, "PREAUTH connection, already authenticated");
884*6236dae4SAndroid Build Coastguard Worker }
885*6236dae4SAndroid Build Coastguard Worker else if(imapcode != IMAP_RESP_OK) {
886*6236dae4SAndroid Build Coastguard Worker failf(data, "Got unexpected imap-server response");
887*6236dae4SAndroid Build Coastguard Worker return CURLE_WEIRD_SERVER_REPLY;
888*6236dae4SAndroid Build Coastguard Worker }
889*6236dae4SAndroid Build Coastguard Worker
890*6236dae4SAndroid Build Coastguard Worker return imap_perform_capability(data, conn);
891*6236dae4SAndroid Build Coastguard Worker }
892*6236dae4SAndroid Build Coastguard Worker
893*6236dae4SAndroid Build Coastguard Worker /* For CAPABILITY responses */
imap_state_capability_resp(struct Curl_easy * data,int imapcode,imapstate instate)894*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_capability_resp(struct Curl_easy *data,
895*6236dae4SAndroid Build Coastguard Worker int imapcode,
896*6236dae4SAndroid Build Coastguard Worker imapstate instate)
897*6236dae4SAndroid Build Coastguard Worker {
898*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
899*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
900*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
901*6236dae4SAndroid Build Coastguard Worker const char *line = Curl_dyn_ptr(&imapc->pp.recvbuf);
902*6236dae4SAndroid Build Coastguard Worker
903*6236dae4SAndroid Build Coastguard Worker (void)instate; /* no use for this yet */
904*6236dae4SAndroid Build Coastguard Worker
905*6236dae4SAndroid Build Coastguard Worker /* Do we have a untagged response? */
906*6236dae4SAndroid Build Coastguard Worker if(imapcode == '*') {
907*6236dae4SAndroid Build Coastguard Worker line += 2;
908*6236dae4SAndroid Build Coastguard Worker
909*6236dae4SAndroid Build Coastguard Worker /* Loop through the data line */
910*6236dae4SAndroid Build Coastguard Worker for(;;) {
911*6236dae4SAndroid Build Coastguard Worker size_t wordlen;
912*6236dae4SAndroid Build Coastguard Worker while(*line &&
913*6236dae4SAndroid Build Coastguard Worker (*line == ' ' || *line == '\t' ||
914*6236dae4SAndroid Build Coastguard Worker *line == '\r' || *line == '\n')) {
915*6236dae4SAndroid Build Coastguard Worker
916*6236dae4SAndroid Build Coastguard Worker line++;
917*6236dae4SAndroid Build Coastguard Worker }
918*6236dae4SAndroid Build Coastguard Worker
919*6236dae4SAndroid Build Coastguard Worker if(!*line)
920*6236dae4SAndroid Build Coastguard Worker break;
921*6236dae4SAndroid Build Coastguard Worker
922*6236dae4SAndroid Build Coastguard Worker /* Extract the word */
923*6236dae4SAndroid Build Coastguard Worker for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' &&
924*6236dae4SAndroid Build Coastguard Worker line[wordlen] != '\t' && line[wordlen] != '\r' &&
925*6236dae4SAndroid Build Coastguard Worker line[wordlen] != '\n';)
926*6236dae4SAndroid Build Coastguard Worker wordlen++;
927*6236dae4SAndroid Build Coastguard Worker
928*6236dae4SAndroid Build Coastguard Worker /* Does the server support the STARTTLS capability? */
929*6236dae4SAndroid Build Coastguard Worker if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
930*6236dae4SAndroid Build Coastguard Worker imapc->tls_supported = TRUE;
931*6236dae4SAndroid Build Coastguard Worker
932*6236dae4SAndroid Build Coastguard Worker /* Has the server explicitly disabled clear text authentication? */
933*6236dae4SAndroid Build Coastguard Worker else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
934*6236dae4SAndroid Build Coastguard Worker imapc->login_disabled = TRUE;
935*6236dae4SAndroid Build Coastguard Worker
936*6236dae4SAndroid Build Coastguard Worker /* Does the server support the SASL-IR capability? */
937*6236dae4SAndroid Build Coastguard Worker else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
938*6236dae4SAndroid Build Coastguard Worker imapc->ir_supported = TRUE;
939*6236dae4SAndroid Build Coastguard Worker
940*6236dae4SAndroid Build Coastguard Worker /* Do we have a SASL based authentication mechanism? */
941*6236dae4SAndroid Build Coastguard Worker else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
942*6236dae4SAndroid Build Coastguard Worker size_t llen;
943*6236dae4SAndroid Build Coastguard Worker unsigned short mechbit;
944*6236dae4SAndroid Build Coastguard Worker
945*6236dae4SAndroid Build Coastguard Worker line += 5;
946*6236dae4SAndroid Build Coastguard Worker wordlen -= 5;
947*6236dae4SAndroid Build Coastguard Worker
948*6236dae4SAndroid Build Coastguard Worker /* Test the word for a matching authentication mechanism */
949*6236dae4SAndroid Build Coastguard Worker mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
950*6236dae4SAndroid Build Coastguard Worker if(mechbit && llen == wordlen)
951*6236dae4SAndroid Build Coastguard Worker imapc->sasl.authmechs |= mechbit;
952*6236dae4SAndroid Build Coastguard Worker }
953*6236dae4SAndroid Build Coastguard Worker
954*6236dae4SAndroid Build Coastguard Worker line += wordlen;
955*6236dae4SAndroid Build Coastguard Worker }
956*6236dae4SAndroid Build Coastguard Worker }
957*6236dae4SAndroid Build Coastguard Worker else if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
958*6236dae4SAndroid Build Coastguard Worker /* PREAUTH is not compatible with STARTTLS. */
959*6236dae4SAndroid Build Coastguard Worker if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
960*6236dae4SAndroid Build Coastguard Worker /* Switch to TLS connection now */
961*6236dae4SAndroid Build Coastguard Worker result = imap_perform_starttls(data);
962*6236dae4SAndroid Build Coastguard Worker }
963*6236dae4SAndroid Build Coastguard Worker else if(data->set.use_ssl <= CURLUSESSL_TRY)
964*6236dae4SAndroid Build Coastguard Worker result = imap_perform_authentication(data, conn);
965*6236dae4SAndroid Build Coastguard Worker else {
966*6236dae4SAndroid Build Coastguard Worker failf(data, "STARTTLS not available.");
967*6236dae4SAndroid Build Coastguard Worker result = CURLE_USE_SSL_FAILED;
968*6236dae4SAndroid Build Coastguard Worker }
969*6236dae4SAndroid Build Coastguard Worker }
970*6236dae4SAndroid Build Coastguard Worker else
971*6236dae4SAndroid Build Coastguard Worker result = imap_perform_authentication(data, conn);
972*6236dae4SAndroid Build Coastguard Worker
973*6236dae4SAndroid Build Coastguard Worker return result;
974*6236dae4SAndroid Build Coastguard Worker }
975*6236dae4SAndroid Build Coastguard Worker
976*6236dae4SAndroid Build Coastguard Worker /* For STARTTLS responses */
imap_state_starttls_resp(struct Curl_easy * data,int imapcode,imapstate instate)977*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_starttls_resp(struct Curl_easy *data,
978*6236dae4SAndroid Build Coastguard Worker int imapcode,
979*6236dae4SAndroid Build Coastguard Worker imapstate instate)
980*6236dae4SAndroid Build Coastguard Worker {
981*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
982*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
983*6236dae4SAndroid Build Coastguard Worker
984*6236dae4SAndroid Build Coastguard Worker (void)instate; /* no use for this yet */
985*6236dae4SAndroid Build Coastguard Worker
986*6236dae4SAndroid Build Coastguard Worker /* Pipelining in response is forbidden. */
987*6236dae4SAndroid Build Coastguard Worker if(data->conn->proto.imapc.pp.overflow)
988*6236dae4SAndroid Build Coastguard Worker return CURLE_WEIRD_SERVER_REPLY;
989*6236dae4SAndroid Build Coastguard Worker
990*6236dae4SAndroid Build Coastguard Worker if(imapcode != IMAP_RESP_OK) {
991*6236dae4SAndroid Build Coastguard Worker if(data->set.use_ssl != CURLUSESSL_TRY) {
992*6236dae4SAndroid Build Coastguard Worker failf(data, "STARTTLS denied");
993*6236dae4SAndroid Build Coastguard Worker result = CURLE_USE_SSL_FAILED;
994*6236dae4SAndroid Build Coastguard Worker }
995*6236dae4SAndroid Build Coastguard Worker else
996*6236dae4SAndroid Build Coastguard Worker result = imap_perform_authentication(data, conn);
997*6236dae4SAndroid Build Coastguard Worker }
998*6236dae4SAndroid Build Coastguard Worker else
999*6236dae4SAndroid Build Coastguard Worker result = imap_perform_upgrade_tls(data, conn);
1000*6236dae4SAndroid Build Coastguard Worker
1001*6236dae4SAndroid Build Coastguard Worker return result;
1002*6236dae4SAndroid Build Coastguard Worker }
1003*6236dae4SAndroid Build Coastguard Worker
1004*6236dae4SAndroid Build Coastguard Worker /* For SASL authentication responses */
imap_state_auth_resp(struct Curl_easy * data,struct connectdata * conn,int imapcode,imapstate instate)1005*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_auth_resp(struct Curl_easy *data,
1006*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
1007*6236dae4SAndroid Build Coastguard Worker int imapcode,
1008*6236dae4SAndroid Build Coastguard Worker imapstate instate)
1009*6236dae4SAndroid Build Coastguard Worker {
1010*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1011*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
1012*6236dae4SAndroid Build Coastguard Worker saslprogress progress;
1013*6236dae4SAndroid Build Coastguard Worker
1014*6236dae4SAndroid Build Coastguard Worker (void)instate; /* no use for this yet */
1015*6236dae4SAndroid Build Coastguard Worker
1016*6236dae4SAndroid Build Coastguard Worker result = Curl_sasl_continue(&imapc->sasl, data, imapcode, &progress);
1017*6236dae4SAndroid Build Coastguard Worker if(!result)
1018*6236dae4SAndroid Build Coastguard Worker switch(progress) {
1019*6236dae4SAndroid Build Coastguard Worker case SASL_DONE:
1020*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP); /* Authenticated */
1021*6236dae4SAndroid Build Coastguard Worker break;
1022*6236dae4SAndroid Build Coastguard Worker case SASL_IDLE: /* No mechanism left after cancellation */
1023*6236dae4SAndroid Build Coastguard Worker if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
1024*6236dae4SAndroid Build Coastguard Worker /* Perform clear text authentication */
1025*6236dae4SAndroid Build Coastguard Worker result = imap_perform_login(data, conn);
1026*6236dae4SAndroid Build Coastguard Worker else {
1027*6236dae4SAndroid Build Coastguard Worker failf(data, "Authentication cancelled");
1028*6236dae4SAndroid Build Coastguard Worker result = CURLE_LOGIN_DENIED;
1029*6236dae4SAndroid Build Coastguard Worker }
1030*6236dae4SAndroid Build Coastguard Worker break;
1031*6236dae4SAndroid Build Coastguard Worker default:
1032*6236dae4SAndroid Build Coastguard Worker break;
1033*6236dae4SAndroid Build Coastguard Worker }
1034*6236dae4SAndroid Build Coastguard Worker
1035*6236dae4SAndroid Build Coastguard Worker return result;
1036*6236dae4SAndroid Build Coastguard Worker }
1037*6236dae4SAndroid Build Coastguard Worker
1038*6236dae4SAndroid Build Coastguard Worker /* For LOGIN responses */
imap_state_login_resp(struct Curl_easy * data,int imapcode,imapstate instate)1039*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_login_resp(struct Curl_easy *data,
1040*6236dae4SAndroid Build Coastguard Worker int imapcode,
1041*6236dae4SAndroid Build Coastguard Worker imapstate instate)
1042*6236dae4SAndroid Build Coastguard Worker {
1043*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1044*6236dae4SAndroid Build Coastguard Worker (void)instate; /* no use for this yet */
1045*6236dae4SAndroid Build Coastguard Worker
1046*6236dae4SAndroid Build Coastguard Worker if(imapcode != IMAP_RESP_OK) {
1047*6236dae4SAndroid Build Coastguard Worker failf(data, "Access denied. %c", imapcode);
1048*6236dae4SAndroid Build Coastguard Worker result = CURLE_LOGIN_DENIED;
1049*6236dae4SAndroid Build Coastguard Worker }
1050*6236dae4SAndroid Build Coastguard Worker else
1051*6236dae4SAndroid Build Coastguard Worker /* End of connect phase */
1052*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
1053*6236dae4SAndroid Build Coastguard Worker
1054*6236dae4SAndroid Build Coastguard Worker return result;
1055*6236dae4SAndroid Build Coastguard Worker }
1056*6236dae4SAndroid Build Coastguard Worker
1057*6236dae4SAndroid Build Coastguard Worker /* For LIST and SEARCH responses */
imap_state_listsearch_resp(struct Curl_easy * data,int imapcode,imapstate instate)1058*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_listsearch_resp(struct Curl_easy *data,
1059*6236dae4SAndroid Build Coastguard Worker int imapcode,
1060*6236dae4SAndroid Build Coastguard Worker imapstate instate)
1061*6236dae4SAndroid Build Coastguard Worker {
1062*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1063*6236dae4SAndroid Build Coastguard Worker char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
1064*6236dae4SAndroid Build Coastguard Worker size_t len = data->conn->proto.imapc.pp.nfinal;
1065*6236dae4SAndroid Build Coastguard Worker
1066*6236dae4SAndroid Build Coastguard Worker (void)instate; /* No use for this yet */
1067*6236dae4SAndroid Build Coastguard Worker
1068*6236dae4SAndroid Build Coastguard Worker if(imapcode == '*')
1069*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
1070*6236dae4SAndroid Build Coastguard Worker else if(imapcode != IMAP_RESP_OK)
1071*6236dae4SAndroid Build Coastguard Worker result = CURLE_QUOTE_ERROR;
1072*6236dae4SAndroid Build Coastguard Worker else
1073*6236dae4SAndroid Build Coastguard Worker /* End of DO phase */
1074*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
1075*6236dae4SAndroid Build Coastguard Worker
1076*6236dae4SAndroid Build Coastguard Worker return result;
1077*6236dae4SAndroid Build Coastguard Worker }
1078*6236dae4SAndroid Build Coastguard Worker
1079*6236dae4SAndroid Build Coastguard Worker /* For SELECT responses */
imap_state_select_resp(struct Curl_easy * data,int imapcode,imapstate instate)1080*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
1081*6236dae4SAndroid Build Coastguard Worker imapstate instate)
1082*6236dae4SAndroid Build Coastguard Worker {
1083*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1084*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
1085*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
1086*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
1087*6236dae4SAndroid Build Coastguard Worker const char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
1088*6236dae4SAndroid Build Coastguard Worker
1089*6236dae4SAndroid Build Coastguard Worker (void)instate; /* no use for this yet */
1090*6236dae4SAndroid Build Coastguard Worker
1091*6236dae4SAndroid Build Coastguard Worker if(imapcode == '*') {
1092*6236dae4SAndroid Build Coastguard Worker /* See if this is an UIDVALIDITY response */
1093*6236dae4SAndroid Build Coastguard Worker if(checkprefix("OK [UIDVALIDITY ", line + 2)) {
1094*6236dae4SAndroid Build Coastguard Worker size_t len = 0;
1095*6236dae4SAndroid Build Coastguard Worker const char *p = &line[2] + strlen("OK [UIDVALIDITY ");
1096*6236dae4SAndroid Build Coastguard Worker while((len < 20) && p[len] && ISDIGIT(p[len]))
1097*6236dae4SAndroid Build Coastguard Worker len++;
1098*6236dae4SAndroid Build Coastguard Worker if(len && (p[len] == ']')) {
1099*6236dae4SAndroid Build Coastguard Worker struct dynbuf uid;
1100*6236dae4SAndroid Build Coastguard Worker Curl_dyn_init(&uid, 20);
1101*6236dae4SAndroid Build Coastguard Worker if(Curl_dyn_addn(&uid, p, len))
1102*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
1103*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imapc->mailbox_uidvalidity);
1104*6236dae4SAndroid Build Coastguard Worker imapc->mailbox_uidvalidity = Curl_dyn_ptr(&uid);
1105*6236dae4SAndroid Build Coastguard Worker }
1106*6236dae4SAndroid Build Coastguard Worker }
1107*6236dae4SAndroid Build Coastguard Worker }
1108*6236dae4SAndroid Build Coastguard Worker else if(imapcode == IMAP_RESP_OK) {
1109*6236dae4SAndroid Build Coastguard Worker /* Check if the UIDVALIDITY has been specified and matches */
1110*6236dae4SAndroid Build Coastguard Worker if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
1111*6236dae4SAndroid Build Coastguard Worker !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
1112*6236dae4SAndroid Build Coastguard Worker failf(data, "Mailbox UIDVALIDITY has changed");
1113*6236dae4SAndroid Build Coastguard Worker result = CURLE_REMOTE_FILE_NOT_FOUND;
1114*6236dae4SAndroid Build Coastguard Worker }
1115*6236dae4SAndroid Build Coastguard Worker else {
1116*6236dae4SAndroid Build Coastguard Worker /* Note the currently opened mailbox on this connection */
1117*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(!imapc->mailbox);
1118*6236dae4SAndroid Build Coastguard Worker imapc->mailbox = strdup(imap->mailbox);
1119*6236dae4SAndroid Build Coastguard Worker if(!imapc->mailbox)
1120*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
1121*6236dae4SAndroid Build Coastguard Worker
1122*6236dae4SAndroid Build Coastguard Worker if(imap->custom)
1123*6236dae4SAndroid Build Coastguard Worker result = imap_perform_list(data);
1124*6236dae4SAndroid Build Coastguard Worker else if(imap->query)
1125*6236dae4SAndroid Build Coastguard Worker result = imap_perform_search(data);
1126*6236dae4SAndroid Build Coastguard Worker else
1127*6236dae4SAndroid Build Coastguard Worker result = imap_perform_fetch(data);
1128*6236dae4SAndroid Build Coastguard Worker }
1129*6236dae4SAndroid Build Coastguard Worker }
1130*6236dae4SAndroid Build Coastguard Worker else {
1131*6236dae4SAndroid Build Coastguard Worker failf(data, "Select failed");
1132*6236dae4SAndroid Build Coastguard Worker result = CURLE_LOGIN_DENIED;
1133*6236dae4SAndroid Build Coastguard Worker }
1134*6236dae4SAndroid Build Coastguard Worker
1135*6236dae4SAndroid Build Coastguard Worker return result;
1136*6236dae4SAndroid Build Coastguard Worker }
1137*6236dae4SAndroid Build Coastguard Worker
1138*6236dae4SAndroid Build Coastguard Worker /* For the (first line of the) FETCH responses */
imap_state_fetch_resp(struct Curl_easy * data,struct connectdata * conn,int imapcode,imapstate instate)1139*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
1140*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn, int imapcode,
1141*6236dae4SAndroid Build Coastguard Worker imapstate instate)
1142*6236dae4SAndroid Build Coastguard Worker {
1143*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1144*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
1145*6236dae4SAndroid Build Coastguard Worker struct pingpong *pp = &imapc->pp;
1146*6236dae4SAndroid Build Coastguard Worker const char *ptr = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
1147*6236dae4SAndroid Build Coastguard Worker size_t len = data->conn->proto.imapc.pp.nfinal;
1148*6236dae4SAndroid Build Coastguard Worker bool parsed = FALSE;
1149*6236dae4SAndroid Build Coastguard Worker curl_off_t size = 0;
1150*6236dae4SAndroid Build Coastguard Worker
1151*6236dae4SAndroid Build Coastguard Worker (void)instate; /* no use for this yet */
1152*6236dae4SAndroid Build Coastguard Worker
1153*6236dae4SAndroid Build Coastguard Worker if(imapcode != '*') {
1154*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadSize(data, -1);
1155*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
1156*6236dae4SAndroid Build Coastguard Worker return CURLE_REMOTE_FILE_NOT_FOUND;
1157*6236dae4SAndroid Build Coastguard Worker }
1158*6236dae4SAndroid Build Coastguard Worker
1159*6236dae4SAndroid Build Coastguard Worker /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse
1160*6236dae4SAndroid Build Coastguard Worker the continuation data contained within the curly brackets */
1161*6236dae4SAndroid Build Coastguard Worker ptr = memchr(ptr, '{', len);
1162*6236dae4SAndroid Build Coastguard Worker if(ptr) {
1163*6236dae4SAndroid Build Coastguard Worker char *endptr;
1164*6236dae4SAndroid Build Coastguard Worker if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) &&
1165*6236dae4SAndroid Build Coastguard Worker (endptr - ptr > 1 && *endptr == '}'))
1166*6236dae4SAndroid Build Coastguard Worker parsed = TRUE;
1167*6236dae4SAndroid Build Coastguard Worker }
1168*6236dae4SAndroid Build Coastguard Worker
1169*6236dae4SAndroid Build Coastguard Worker if(parsed) {
1170*6236dae4SAndroid Build Coastguard Worker infof(data, "Found %" FMT_OFF_T " bytes to download", size);
1171*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadSize(data, size);
1172*6236dae4SAndroid Build Coastguard Worker
1173*6236dae4SAndroid Build Coastguard Worker if(pp->overflow) {
1174*6236dae4SAndroid Build Coastguard Worker /* At this point there is a data in the receive buffer that is body
1175*6236dae4SAndroid Build Coastguard Worker content, send it as body and then skip it. Do note that there may
1176*6236dae4SAndroid Build Coastguard Worker even be additional "headers" after the body. */
1177*6236dae4SAndroid Build Coastguard Worker size_t chunk = pp->overflow;
1178*6236dae4SAndroid Build Coastguard Worker
1179*6236dae4SAndroid Build Coastguard Worker /* keep only the overflow */
1180*6236dae4SAndroid Build Coastguard Worker Curl_dyn_tail(&pp->recvbuf, chunk);
1181*6236dae4SAndroid Build Coastguard Worker pp->nfinal = 0; /* done */
1182*6236dae4SAndroid Build Coastguard Worker
1183*6236dae4SAndroid Build Coastguard Worker if(chunk > (size_t)size)
1184*6236dae4SAndroid Build Coastguard Worker /* The conversion from curl_off_t to size_t is always fine here */
1185*6236dae4SAndroid Build Coastguard Worker chunk = (size_t)size;
1186*6236dae4SAndroid Build Coastguard Worker
1187*6236dae4SAndroid Build Coastguard Worker if(!chunk) {
1188*6236dae4SAndroid Build Coastguard Worker /* no size, we are done with the data */
1189*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
1190*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1191*6236dae4SAndroid Build Coastguard Worker }
1192*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_BODY,
1193*6236dae4SAndroid Build Coastguard Worker Curl_dyn_ptr(&pp->recvbuf), chunk);
1194*6236dae4SAndroid Build Coastguard Worker if(result)
1195*6236dae4SAndroid Build Coastguard Worker return result;
1196*6236dae4SAndroid Build Coastguard Worker
1197*6236dae4SAndroid Build Coastguard Worker infof(data, "Written %zu bytes, %" FMT_OFF_TU
1198*6236dae4SAndroid Build Coastguard Worker " bytes are left for transfer", chunk, size - chunk);
1199*6236dae4SAndroid Build Coastguard Worker
1200*6236dae4SAndroid Build Coastguard Worker /* Have we used the entire overflow or just part of it?*/
1201*6236dae4SAndroid Build Coastguard Worker if(pp->overflow > chunk) {
1202*6236dae4SAndroid Build Coastguard Worker /* remember the remaining trailing overflow data */
1203*6236dae4SAndroid Build Coastguard Worker pp->overflow -= chunk;
1204*6236dae4SAndroid Build Coastguard Worker Curl_dyn_tail(&pp->recvbuf, pp->overflow);
1205*6236dae4SAndroid Build Coastguard Worker }
1206*6236dae4SAndroid Build Coastguard Worker else {
1207*6236dae4SAndroid Build Coastguard Worker pp->overflow = 0; /* handled */
1208*6236dae4SAndroid Build Coastguard Worker /* Free the cache */
1209*6236dae4SAndroid Build Coastguard Worker Curl_dyn_reset(&pp->recvbuf);
1210*6236dae4SAndroid Build Coastguard Worker }
1211*6236dae4SAndroid Build Coastguard Worker }
1212*6236dae4SAndroid Build Coastguard Worker
1213*6236dae4SAndroid Build Coastguard Worker if(data->req.bytecount == size)
1214*6236dae4SAndroid Build Coastguard Worker /* The entire data is already transferred! */
1215*6236dae4SAndroid Build Coastguard Worker Curl_xfer_setup_nop(data);
1216*6236dae4SAndroid Build Coastguard Worker else {
1217*6236dae4SAndroid Build Coastguard Worker /* IMAP download */
1218*6236dae4SAndroid Build Coastguard Worker data->req.maxdownload = size;
1219*6236dae4SAndroid Build Coastguard Worker /* force a recv/send check of this connection, as the data might've been
1220*6236dae4SAndroid Build Coastguard Worker read off the socket already */
1221*6236dae4SAndroid Build Coastguard Worker data->state.select_bits = CURL_CSELECT_IN;
1222*6236dae4SAndroid Build Coastguard Worker Curl_xfer_setup1(data, CURL_XFER_RECV, size, FALSE);
1223*6236dae4SAndroid Build Coastguard Worker }
1224*6236dae4SAndroid Build Coastguard Worker }
1225*6236dae4SAndroid Build Coastguard Worker else {
1226*6236dae4SAndroid Build Coastguard Worker /* We do not know how to parse this line */
1227*6236dae4SAndroid Build Coastguard Worker failf(data, "Failed to parse FETCH response.");
1228*6236dae4SAndroid Build Coastguard Worker result = CURLE_WEIRD_SERVER_REPLY;
1229*6236dae4SAndroid Build Coastguard Worker }
1230*6236dae4SAndroid Build Coastguard Worker
1231*6236dae4SAndroid Build Coastguard Worker /* End of DO phase */
1232*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
1233*6236dae4SAndroid Build Coastguard Worker
1234*6236dae4SAndroid Build Coastguard Worker return result;
1235*6236dae4SAndroid Build Coastguard Worker }
1236*6236dae4SAndroid Build Coastguard Worker
1237*6236dae4SAndroid Build Coastguard Worker /* For final FETCH responses performed after the download */
imap_state_fetch_final_resp(struct Curl_easy * data,int imapcode,imapstate instate)1238*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_fetch_final_resp(struct Curl_easy *data,
1239*6236dae4SAndroid Build Coastguard Worker int imapcode,
1240*6236dae4SAndroid Build Coastguard Worker imapstate instate)
1241*6236dae4SAndroid Build Coastguard Worker {
1242*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1243*6236dae4SAndroid Build Coastguard Worker
1244*6236dae4SAndroid Build Coastguard Worker (void)instate; /* No use for this yet */
1245*6236dae4SAndroid Build Coastguard Worker
1246*6236dae4SAndroid Build Coastguard Worker if(imapcode != IMAP_RESP_OK)
1247*6236dae4SAndroid Build Coastguard Worker result = CURLE_WEIRD_SERVER_REPLY;
1248*6236dae4SAndroid Build Coastguard Worker else
1249*6236dae4SAndroid Build Coastguard Worker /* End of DONE phase */
1250*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
1251*6236dae4SAndroid Build Coastguard Worker
1252*6236dae4SAndroid Build Coastguard Worker return result;
1253*6236dae4SAndroid Build Coastguard Worker }
1254*6236dae4SAndroid Build Coastguard Worker
1255*6236dae4SAndroid Build Coastguard Worker /* For APPEND responses */
imap_state_append_resp(struct Curl_easy * data,int imapcode,imapstate instate)1256*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_append_resp(struct Curl_easy *data, int imapcode,
1257*6236dae4SAndroid Build Coastguard Worker imapstate instate)
1258*6236dae4SAndroid Build Coastguard Worker {
1259*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1260*6236dae4SAndroid Build Coastguard Worker (void)instate; /* No use for this yet */
1261*6236dae4SAndroid Build Coastguard Worker
1262*6236dae4SAndroid Build Coastguard Worker if(imapcode != '+') {
1263*6236dae4SAndroid Build Coastguard Worker result = CURLE_UPLOAD_FAILED;
1264*6236dae4SAndroid Build Coastguard Worker }
1265*6236dae4SAndroid Build Coastguard Worker else {
1266*6236dae4SAndroid Build Coastguard Worker /* Set the progress upload size */
1267*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetUploadSize(data, data->state.infilesize);
1268*6236dae4SAndroid Build Coastguard Worker
1269*6236dae4SAndroid Build Coastguard Worker /* IMAP upload */
1270*6236dae4SAndroid Build Coastguard Worker Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
1271*6236dae4SAndroid Build Coastguard Worker
1272*6236dae4SAndroid Build Coastguard Worker /* End of DO phase */
1273*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
1274*6236dae4SAndroid Build Coastguard Worker }
1275*6236dae4SAndroid Build Coastguard Worker
1276*6236dae4SAndroid Build Coastguard Worker return result;
1277*6236dae4SAndroid Build Coastguard Worker }
1278*6236dae4SAndroid Build Coastguard Worker
1279*6236dae4SAndroid Build Coastguard Worker /* For final APPEND responses performed after the upload */
imap_state_append_final_resp(struct Curl_easy * data,int imapcode,imapstate instate)1280*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_state_append_final_resp(struct Curl_easy *data,
1281*6236dae4SAndroid Build Coastguard Worker int imapcode,
1282*6236dae4SAndroid Build Coastguard Worker imapstate instate)
1283*6236dae4SAndroid Build Coastguard Worker {
1284*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1285*6236dae4SAndroid Build Coastguard Worker
1286*6236dae4SAndroid Build Coastguard Worker (void)instate; /* No use for this yet */
1287*6236dae4SAndroid Build Coastguard Worker
1288*6236dae4SAndroid Build Coastguard Worker if(imapcode != IMAP_RESP_OK)
1289*6236dae4SAndroid Build Coastguard Worker result = CURLE_UPLOAD_FAILED;
1290*6236dae4SAndroid Build Coastguard Worker else
1291*6236dae4SAndroid Build Coastguard Worker /* End of DONE phase */
1292*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
1293*6236dae4SAndroid Build Coastguard Worker
1294*6236dae4SAndroid Build Coastguard Worker return result;
1295*6236dae4SAndroid Build Coastguard Worker }
1296*6236dae4SAndroid Build Coastguard Worker
imap_statemachine(struct Curl_easy * data,struct connectdata * conn)1297*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_statemachine(struct Curl_easy *data,
1298*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
1299*6236dae4SAndroid Build Coastguard Worker {
1300*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1301*6236dae4SAndroid Build Coastguard Worker int imapcode;
1302*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
1303*6236dae4SAndroid Build Coastguard Worker struct pingpong *pp = &imapc->pp;
1304*6236dae4SAndroid Build Coastguard Worker size_t nread = 0;
1305*6236dae4SAndroid Build Coastguard Worker (void)data;
1306*6236dae4SAndroid Build Coastguard Worker
1307*6236dae4SAndroid Build Coastguard Worker /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */
1308*6236dae4SAndroid Build Coastguard Worker if(imapc->state == IMAP_UPGRADETLS)
1309*6236dae4SAndroid Build Coastguard Worker return imap_perform_upgrade_tls(data, conn);
1310*6236dae4SAndroid Build Coastguard Worker
1311*6236dae4SAndroid Build Coastguard Worker /* Flush any data that needs to be sent */
1312*6236dae4SAndroid Build Coastguard Worker if(pp->sendleft)
1313*6236dae4SAndroid Build Coastguard Worker return Curl_pp_flushsend(data, pp);
1314*6236dae4SAndroid Build Coastguard Worker
1315*6236dae4SAndroid Build Coastguard Worker do {
1316*6236dae4SAndroid Build Coastguard Worker /* Read the response from the server */
1317*6236dae4SAndroid Build Coastguard Worker result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &imapcode, &nread);
1318*6236dae4SAndroid Build Coastguard Worker if(result)
1319*6236dae4SAndroid Build Coastguard Worker return result;
1320*6236dae4SAndroid Build Coastguard Worker
1321*6236dae4SAndroid Build Coastguard Worker /* Was there an error parsing the response line? */
1322*6236dae4SAndroid Build Coastguard Worker if(imapcode == -1)
1323*6236dae4SAndroid Build Coastguard Worker return CURLE_WEIRD_SERVER_REPLY;
1324*6236dae4SAndroid Build Coastguard Worker
1325*6236dae4SAndroid Build Coastguard Worker if(!imapcode)
1326*6236dae4SAndroid Build Coastguard Worker break;
1327*6236dae4SAndroid Build Coastguard Worker
1328*6236dae4SAndroid Build Coastguard Worker /* We have now received a full IMAP server response */
1329*6236dae4SAndroid Build Coastguard Worker switch(imapc->state) {
1330*6236dae4SAndroid Build Coastguard Worker case IMAP_SERVERGREET:
1331*6236dae4SAndroid Build Coastguard Worker result = imap_state_servergreet_resp(data, imapcode, imapc->state);
1332*6236dae4SAndroid Build Coastguard Worker break;
1333*6236dae4SAndroid Build Coastguard Worker
1334*6236dae4SAndroid Build Coastguard Worker case IMAP_CAPABILITY:
1335*6236dae4SAndroid Build Coastguard Worker result = imap_state_capability_resp(data, imapcode, imapc->state);
1336*6236dae4SAndroid Build Coastguard Worker break;
1337*6236dae4SAndroid Build Coastguard Worker
1338*6236dae4SAndroid Build Coastguard Worker case IMAP_STARTTLS:
1339*6236dae4SAndroid Build Coastguard Worker result = imap_state_starttls_resp(data, imapcode, imapc->state);
1340*6236dae4SAndroid Build Coastguard Worker break;
1341*6236dae4SAndroid Build Coastguard Worker
1342*6236dae4SAndroid Build Coastguard Worker case IMAP_AUTHENTICATE:
1343*6236dae4SAndroid Build Coastguard Worker result = imap_state_auth_resp(data, conn, imapcode, imapc->state);
1344*6236dae4SAndroid Build Coastguard Worker break;
1345*6236dae4SAndroid Build Coastguard Worker
1346*6236dae4SAndroid Build Coastguard Worker case IMAP_LOGIN:
1347*6236dae4SAndroid Build Coastguard Worker result = imap_state_login_resp(data, imapcode, imapc->state);
1348*6236dae4SAndroid Build Coastguard Worker break;
1349*6236dae4SAndroid Build Coastguard Worker
1350*6236dae4SAndroid Build Coastguard Worker case IMAP_LIST:
1351*6236dae4SAndroid Build Coastguard Worker case IMAP_SEARCH:
1352*6236dae4SAndroid Build Coastguard Worker result = imap_state_listsearch_resp(data, imapcode, imapc->state);
1353*6236dae4SAndroid Build Coastguard Worker break;
1354*6236dae4SAndroid Build Coastguard Worker
1355*6236dae4SAndroid Build Coastguard Worker case IMAP_SELECT:
1356*6236dae4SAndroid Build Coastguard Worker result = imap_state_select_resp(data, imapcode, imapc->state);
1357*6236dae4SAndroid Build Coastguard Worker break;
1358*6236dae4SAndroid Build Coastguard Worker
1359*6236dae4SAndroid Build Coastguard Worker case IMAP_FETCH:
1360*6236dae4SAndroid Build Coastguard Worker result = imap_state_fetch_resp(data, conn, imapcode, imapc->state);
1361*6236dae4SAndroid Build Coastguard Worker break;
1362*6236dae4SAndroid Build Coastguard Worker
1363*6236dae4SAndroid Build Coastguard Worker case IMAP_FETCH_FINAL:
1364*6236dae4SAndroid Build Coastguard Worker result = imap_state_fetch_final_resp(data, imapcode, imapc->state);
1365*6236dae4SAndroid Build Coastguard Worker break;
1366*6236dae4SAndroid Build Coastguard Worker
1367*6236dae4SAndroid Build Coastguard Worker case IMAP_APPEND:
1368*6236dae4SAndroid Build Coastguard Worker result = imap_state_append_resp(data, imapcode, imapc->state);
1369*6236dae4SAndroid Build Coastguard Worker break;
1370*6236dae4SAndroid Build Coastguard Worker
1371*6236dae4SAndroid Build Coastguard Worker case IMAP_APPEND_FINAL:
1372*6236dae4SAndroid Build Coastguard Worker result = imap_state_append_final_resp(data, imapcode, imapc->state);
1373*6236dae4SAndroid Build Coastguard Worker break;
1374*6236dae4SAndroid Build Coastguard Worker
1375*6236dae4SAndroid Build Coastguard Worker case IMAP_LOGOUT:
1376*6236dae4SAndroid Build Coastguard Worker default:
1377*6236dae4SAndroid Build Coastguard Worker /* internal error */
1378*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_STOP);
1379*6236dae4SAndroid Build Coastguard Worker break;
1380*6236dae4SAndroid Build Coastguard Worker }
1381*6236dae4SAndroid Build Coastguard Worker } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp));
1382*6236dae4SAndroid Build Coastguard Worker
1383*6236dae4SAndroid Build Coastguard Worker return result;
1384*6236dae4SAndroid Build Coastguard Worker }
1385*6236dae4SAndroid Build Coastguard Worker
1386*6236dae4SAndroid Build Coastguard Worker /* Called repeatedly until done from multi.c */
imap_multi_statemach(struct Curl_easy * data,bool * done)1387*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done)
1388*6236dae4SAndroid Build Coastguard Worker {
1389*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1390*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
1391*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
1392*6236dae4SAndroid Build Coastguard Worker
1393*6236dae4SAndroid Build Coastguard Worker if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
1394*6236dae4SAndroid Build Coastguard Worker bool ssldone = FALSE;
1395*6236dae4SAndroid Build Coastguard Worker result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
1396*6236dae4SAndroid Build Coastguard Worker imapc->ssldone = ssldone;
1397*6236dae4SAndroid Build Coastguard Worker if(result || !ssldone)
1398*6236dae4SAndroid Build Coastguard Worker return result;
1399*6236dae4SAndroid Build Coastguard Worker }
1400*6236dae4SAndroid Build Coastguard Worker
1401*6236dae4SAndroid Build Coastguard Worker result = Curl_pp_statemach(data, &imapc->pp, FALSE, FALSE);
1402*6236dae4SAndroid Build Coastguard Worker *done = (imapc->state == IMAP_STOP);
1403*6236dae4SAndroid Build Coastguard Worker
1404*6236dae4SAndroid Build Coastguard Worker return result;
1405*6236dae4SAndroid Build Coastguard Worker }
1406*6236dae4SAndroid Build Coastguard Worker
imap_block_statemach(struct Curl_easy * data,struct connectdata * conn,bool disconnecting)1407*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_block_statemach(struct Curl_easy *data,
1408*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
1409*6236dae4SAndroid Build Coastguard Worker bool disconnecting)
1410*6236dae4SAndroid Build Coastguard Worker {
1411*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1412*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
1413*6236dae4SAndroid Build Coastguard Worker
1414*6236dae4SAndroid Build Coastguard Worker while(imapc->state != IMAP_STOP && !result)
1415*6236dae4SAndroid Build Coastguard Worker result = Curl_pp_statemach(data, &imapc->pp, TRUE, disconnecting);
1416*6236dae4SAndroid Build Coastguard Worker
1417*6236dae4SAndroid Build Coastguard Worker return result;
1418*6236dae4SAndroid Build Coastguard Worker }
1419*6236dae4SAndroid Build Coastguard Worker
1420*6236dae4SAndroid Build Coastguard Worker /* Allocate and initialize the struct IMAP for the current Curl_easy if
1421*6236dae4SAndroid Build Coastguard Worker required */
imap_init(struct Curl_easy * data)1422*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_init(struct Curl_easy *data)
1423*6236dae4SAndroid Build Coastguard Worker {
1424*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1425*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap;
1426*6236dae4SAndroid Build Coastguard Worker
1427*6236dae4SAndroid Build Coastguard Worker imap = data->req.p.imap = calloc(1, sizeof(struct IMAP));
1428*6236dae4SAndroid Build Coastguard Worker if(!imap)
1429*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
1430*6236dae4SAndroid Build Coastguard Worker
1431*6236dae4SAndroid Build Coastguard Worker return result;
1432*6236dae4SAndroid Build Coastguard Worker }
1433*6236dae4SAndroid Build Coastguard Worker
1434*6236dae4SAndroid Build Coastguard Worker /* For the IMAP "protocol connect" and "doing" phases only */
imap_getsock(struct Curl_easy * data,struct connectdata * conn,curl_socket_t * socks)1435*6236dae4SAndroid Build Coastguard Worker static int imap_getsock(struct Curl_easy *data,
1436*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
1437*6236dae4SAndroid Build Coastguard Worker curl_socket_t *socks)
1438*6236dae4SAndroid Build Coastguard Worker {
1439*6236dae4SAndroid Build Coastguard Worker return Curl_pp_getsock(data, &conn->proto.imapc.pp, socks);
1440*6236dae4SAndroid Build Coastguard Worker }
1441*6236dae4SAndroid Build Coastguard Worker
1442*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1443*6236dae4SAndroid Build Coastguard Worker *
1444*6236dae4SAndroid Build Coastguard Worker * imap_connect()
1445*6236dae4SAndroid Build Coastguard Worker *
1446*6236dae4SAndroid Build Coastguard Worker * This function should do everything that is to be considered a part of the
1447*6236dae4SAndroid Build Coastguard Worker * connection phase.
1448*6236dae4SAndroid Build Coastguard Worker *
1449*6236dae4SAndroid Build Coastguard Worker * The variable 'done' points to will be TRUE if the protocol-layer connect
1450*6236dae4SAndroid Build Coastguard Worker * phase is done when this function returns, or FALSE if not.
1451*6236dae4SAndroid Build Coastguard Worker */
imap_connect(struct Curl_easy * data,bool * done)1452*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_connect(struct Curl_easy *data, bool *done)
1453*6236dae4SAndroid Build Coastguard Worker {
1454*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1455*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
1456*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
1457*6236dae4SAndroid Build Coastguard Worker struct pingpong *pp = &imapc->pp;
1458*6236dae4SAndroid Build Coastguard Worker
1459*6236dae4SAndroid Build Coastguard Worker *done = FALSE; /* default to not done yet */
1460*6236dae4SAndroid Build Coastguard Worker
1461*6236dae4SAndroid Build Coastguard Worker /* We always support persistent connections in IMAP */
1462*6236dae4SAndroid Build Coastguard Worker connkeep(conn, "IMAP default");
1463*6236dae4SAndroid Build Coastguard Worker
1464*6236dae4SAndroid Build Coastguard Worker PINGPONG_SETUP(pp, imap_statemachine, imap_endofresp);
1465*6236dae4SAndroid Build Coastguard Worker
1466*6236dae4SAndroid Build Coastguard Worker /* Set the default preferred authentication type and mechanism */
1467*6236dae4SAndroid Build Coastguard Worker imapc->preftype = IMAP_TYPE_ANY;
1468*6236dae4SAndroid Build Coastguard Worker Curl_sasl_init(&imapc->sasl, data, &saslimap);
1469*6236dae4SAndroid Build Coastguard Worker
1470*6236dae4SAndroid Build Coastguard Worker Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
1471*6236dae4SAndroid Build Coastguard Worker Curl_pp_init(pp);
1472*6236dae4SAndroid Build Coastguard Worker
1473*6236dae4SAndroid Build Coastguard Worker /* Parse the URL options */
1474*6236dae4SAndroid Build Coastguard Worker result = imap_parse_url_options(conn);
1475*6236dae4SAndroid Build Coastguard Worker if(result)
1476*6236dae4SAndroid Build Coastguard Worker return result;
1477*6236dae4SAndroid Build Coastguard Worker
1478*6236dae4SAndroid Build Coastguard Worker /* Start off waiting for the server greeting response */
1479*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_SERVERGREET);
1480*6236dae4SAndroid Build Coastguard Worker
1481*6236dae4SAndroid Build Coastguard Worker /* Start off with an response id of '*' */
1482*6236dae4SAndroid Build Coastguard Worker strcpy(imapc->resptag, "*");
1483*6236dae4SAndroid Build Coastguard Worker
1484*6236dae4SAndroid Build Coastguard Worker result = imap_multi_statemach(data, done);
1485*6236dae4SAndroid Build Coastguard Worker
1486*6236dae4SAndroid Build Coastguard Worker return result;
1487*6236dae4SAndroid Build Coastguard Worker }
1488*6236dae4SAndroid Build Coastguard Worker
1489*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1490*6236dae4SAndroid Build Coastguard Worker *
1491*6236dae4SAndroid Build Coastguard Worker * imap_done()
1492*6236dae4SAndroid Build Coastguard Worker *
1493*6236dae4SAndroid Build Coastguard Worker * The DONE function. This does what needs to be done after a single DO has
1494*6236dae4SAndroid Build Coastguard Worker * performed.
1495*6236dae4SAndroid Build Coastguard Worker *
1496*6236dae4SAndroid Build Coastguard Worker * Input argument is already checked for validity.
1497*6236dae4SAndroid Build Coastguard Worker */
imap_done(struct Curl_easy * data,CURLcode status,bool premature)1498*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
1499*6236dae4SAndroid Build Coastguard Worker bool premature)
1500*6236dae4SAndroid Build Coastguard Worker {
1501*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1502*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
1503*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
1504*6236dae4SAndroid Build Coastguard Worker
1505*6236dae4SAndroid Build Coastguard Worker (void)premature;
1506*6236dae4SAndroid Build Coastguard Worker
1507*6236dae4SAndroid Build Coastguard Worker if(!imap)
1508*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1509*6236dae4SAndroid Build Coastguard Worker
1510*6236dae4SAndroid Build Coastguard Worker if(status) {
1511*6236dae4SAndroid Build Coastguard Worker connclose(conn, "IMAP done with bad status"); /* marked for closure */
1512*6236dae4SAndroid Build Coastguard Worker result = status; /* use the already set error code */
1513*6236dae4SAndroid Build Coastguard Worker }
1514*6236dae4SAndroid Build Coastguard Worker else if(!data->set.connect_only && !imap->custom &&
1515*6236dae4SAndroid Build Coastguard Worker (imap->uid || imap->mindex || data->state.upload ||
1516*6236dae4SAndroid Build Coastguard Worker IS_MIME_POST(data))) {
1517*6236dae4SAndroid Build Coastguard Worker /* Handle responses after FETCH or APPEND transfer has finished */
1518*6236dae4SAndroid Build Coastguard Worker
1519*6236dae4SAndroid Build Coastguard Worker if(!data->state.upload && !IS_MIME_POST(data))
1520*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_FETCH_FINAL);
1521*6236dae4SAndroid Build Coastguard Worker else {
1522*6236dae4SAndroid Build Coastguard Worker /* End the APPEND command first by sending an empty line */
1523*6236dae4SAndroid Build Coastguard Worker result = Curl_pp_sendf(data, &conn->proto.imapc.pp, "%s", "");
1524*6236dae4SAndroid Build Coastguard Worker if(!result)
1525*6236dae4SAndroid Build Coastguard Worker imap_state(data, IMAP_APPEND_FINAL);
1526*6236dae4SAndroid Build Coastguard Worker }
1527*6236dae4SAndroid Build Coastguard Worker
1528*6236dae4SAndroid Build Coastguard Worker /* Run the state-machine */
1529*6236dae4SAndroid Build Coastguard Worker if(!result)
1530*6236dae4SAndroid Build Coastguard Worker result = imap_block_statemach(data, conn, FALSE);
1531*6236dae4SAndroid Build Coastguard Worker }
1532*6236dae4SAndroid Build Coastguard Worker
1533*6236dae4SAndroid Build Coastguard Worker /* Cleanup our per-request based variables */
1534*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imap->mailbox);
1535*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imap->uidvalidity);
1536*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imap->uid);
1537*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imap->mindex);
1538*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imap->section);
1539*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imap->partial);
1540*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imap->query);
1541*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imap->custom);
1542*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imap->custom_params);
1543*6236dae4SAndroid Build Coastguard Worker
1544*6236dae4SAndroid Build Coastguard Worker /* Clear the transfer mode for the next request */
1545*6236dae4SAndroid Build Coastguard Worker imap->transfer = PPTRANSFER_BODY;
1546*6236dae4SAndroid Build Coastguard Worker
1547*6236dae4SAndroid Build Coastguard Worker return result;
1548*6236dae4SAndroid Build Coastguard Worker }
1549*6236dae4SAndroid Build Coastguard Worker
1550*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1551*6236dae4SAndroid Build Coastguard Worker *
1552*6236dae4SAndroid Build Coastguard Worker * imap_perform()
1553*6236dae4SAndroid Build Coastguard Worker *
1554*6236dae4SAndroid Build Coastguard Worker * This is the actual DO function for IMAP. Fetch or append a message, or do
1555*6236dae4SAndroid Build Coastguard Worker * other things according to the options previously setup.
1556*6236dae4SAndroid Build Coastguard Worker */
imap_perform(struct Curl_easy * data,bool * connected,bool * dophase_done)1557*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
1558*6236dae4SAndroid Build Coastguard Worker bool *dophase_done)
1559*6236dae4SAndroid Build Coastguard Worker {
1560*6236dae4SAndroid Build Coastguard Worker /* This is IMAP and no proxy */
1561*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1562*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn = data->conn;
1563*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
1564*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
1565*6236dae4SAndroid Build Coastguard Worker bool selected = FALSE;
1566*6236dae4SAndroid Build Coastguard Worker
1567*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "DO phase starts"));
1568*6236dae4SAndroid Build Coastguard Worker
1569*6236dae4SAndroid Build Coastguard Worker if(data->req.no_body) {
1570*6236dae4SAndroid Build Coastguard Worker /* Requested no body means no transfer */
1571*6236dae4SAndroid Build Coastguard Worker imap->transfer = PPTRANSFER_INFO;
1572*6236dae4SAndroid Build Coastguard Worker }
1573*6236dae4SAndroid Build Coastguard Worker
1574*6236dae4SAndroid Build Coastguard Worker *dophase_done = FALSE; /* not done yet */
1575*6236dae4SAndroid Build Coastguard Worker
1576*6236dae4SAndroid Build Coastguard Worker /* Determine if the requested mailbox (with the same UIDVALIDITY if set)
1577*6236dae4SAndroid Build Coastguard Worker has already been selected on this connection */
1578*6236dae4SAndroid Build Coastguard Worker if(imap->mailbox && imapc->mailbox &&
1579*6236dae4SAndroid Build Coastguard Worker strcasecompare(imap->mailbox, imapc->mailbox) &&
1580*6236dae4SAndroid Build Coastguard Worker (!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
1581*6236dae4SAndroid Build Coastguard Worker strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)))
1582*6236dae4SAndroid Build Coastguard Worker selected = TRUE;
1583*6236dae4SAndroid Build Coastguard Worker
1584*6236dae4SAndroid Build Coastguard Worker /* Start the first command in the DO phase */
1585*6236dae4SAndroid Build Coastguard Worker if(data->state.upload || IS_MIME_POST(data))
1586*6236dae4SAndroid Build Coastguard Worker /* APPEND can be executed directly */
1587*6236dae4SAndroid Build Coastguard Worker result = imap_perform_append(data);
1588*6236dae4SAndroid Build Coastguard Worker else if(imap->custom && (selected || !imap->mailbox))
1589*6236dae4SAndroid Build Coastguard Worker /* Custom command using the same mailbox or no mailbox */
1590*6236dae4SAndroid Build Coastguard Worker result = imap_perform_list(data);
1591*6236dae4SAndroid Build Coastguard Worker else if(!imap->custom && selected && (imap->uid || imap->mindex))
1592*6236dae4SAndroid Build Coastguard Worker /* FETCH from the same mailbox */
1593*6236dae4SAndroid Build Coastguard Worker result = imap_perform_fetch(data);
1594*6236dae4SAndroid Build Coastguard Worker else if(!imap->custom && selected && imap->query)
1595*6236dae4SAndroid Build Coastguard Worker /* SEARCH the current mailbox */
1596*6236dae4SAndroid Build Coastguard Worker result = imap_perform_search(data);
1597*6236dae4SAndroid Build Coastguard Worker else if(imap->mailbox && !selected &&
1598*6236dae4SAndroid Build Coastguard Worker (imap->custom || imap->uid || imap->mindex || imap->query))
1599*6236dae4SAndroid Build Coastguard Worker /* SELECT the mailbox */
1600*6236dae4SAndroid Build Coastguard Worker result = imap_perform_select(data);
1601*6236dae4SAndroid Build Coastguard Worker else
1602*6236dae4SAndroid Build Coastguard Worker /* LIST */
1603*6236dae4SAndroid Build Coastguard Worker result = imap_perform_list(data);
1604*6236dae4SAndroid Build Coastguard Worker
1605*6236dae4SAndroid Build Coastguard Worker if(result)
1606*6236dae4SAndroid Build Coastguard Worker return result;
1607*6236dae4SAndroid Build Coastguard Worker
1608*6236dae4SAndroid Build Coastguard Worker /* Run the state-machine */
1609*6236dae4SAndroid Build Coastguard Worker result = imap_multi_statemach(data, dophase_done);
1610*6236dae4SAndroid Build Coastguard Worker
1611*6236dae4SAndroid Build Coastguard Worker *connected = Curl_conn_is_connected(conn, FIRSTSOCKET);
1612*6236dae4SAndroid Build Coastguard Worker
1613*6236dae4SAndroid Build Coastguard Worker if(*dophase_done)
1614*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "DO phase is complete"));
1615*6236dae4SAndroid Build Coastguard Worker
1616*6236dae4SAndroid Build Coastguard Worker return result;
1617*6236dae4SAndroid Build Coastguard Worker }
1618*6236dae4SAndroid Build Coastguard Worker
1619*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1620*6236dae4SAndroid Build Coastguard Worker *
1621*6236dae4SAndroid Build Coastguard Worker * imap_do()
1622*6236dae4SAndroid Build Coastguard Worker *
1623*6236dae4SAndroid Build Coastguard Worker * This function is registered as 'curl_do' function. It decodes the path
1624*6236dae4SAndroid Build Coastguard Worker * parts etc as a wrapper to the actual DO function (imap_perform).
1625*6236dae4SAndroid Build Coastguard Worker *
1626*6236dae4SAndroid Build Coastguard Worker * The input argument is already checked for validity.
1627*6236dae4SAndroid Build Coastguard Worker */
imap_do(struct Curl_easy * data,bool * done)1628*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_do(struct Curl_easy *data, bool *done)
1629*6236dae4SAndroid Build Coastguard Worker {
1630*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1631*6236dae4SAndroid Build Coastguard Worker *done = FALSE; /* default to false */
1632*6236dae4SAndroid Build Coastguard Worker
1633*6236dae4SAndroid Build Coastguard Worker /* Parse the URL path */
1634*6236dae4SAndroid Build Coastguard Worker result = imap_parse_url_path(data);
1635*6236dae4SAndroid Build Coastguard Worker if(result)
1636*6236dae4SAndroid Build Coastguard Worker return result;
1637*6236dae4SAndroid Build Coastguard Worker
1638*6236dae4SAndroid Build Coastguard Worker /* Parse the custom request */
1639*6236dae4SAndroid Build Coastguard Worker result = imap_parse_custom_request(data);
1640*6236dae4SAndroid Build Coastguard Worker if(result)
1641*6236dae4SAndroid Build Coastguard Worker return result;
1642*6236dae4SAndroid Build Coastguard Worker
1643*6236dae4SAndroid Build Coastguard Worker result = imap_regular_transfer(data, done);
1644*6236dae4SAndroid Build Coastguard Worker
1645*6236dae4SAndroid Build Coastguard Worker return result;
1646*6236dae4SAndroid Build Coastguard Worker }
1647*6236dae4SAndroid Build Coastguard Worker
1648*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1649*6236dae4SAndroid Build Coastguard Worker *
1650*6236dae4SAndroid Build Coastguard Worker * imap_disconnect()
1651*6236dae4SAndroid Build Coastguard Worker *
1652*6236dae4SAndroid Build Coastguard Worker * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
1653*6236dae4SAndroid Build Coastguard Worker * resources. BLOCKING.
1654*6236dae4SAndroid Build Coastguard Worker */
imap_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)1655*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_disconnect(struct Curl_easy *data,
1656*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn, bool dead_connection)
1657*6236dae4SAndroid Build Coastguard Worker {
1658*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
1659*6236dae4SAndroid Build Coastguard Worker (void)data;
1660*6236dae4SAndroid Build Coastguard Worker
1661*6236dae4SAndroid Build Coastguard Worker /* We cannot send quit unconditionally. If this connection is stale or
1662*6236dae4SAndroid Build Coastguard Worker bad in any way, sending quit and waiting around here will make the
1663*6236dae4SAndroid Build Coastguard Worker disconnect wait in vain and cause more problems than we need to. */
1664*6236dae4SAndroid Build Coastguard Worker
1665*6236dae4SAndroid Build Coastguard Worker /* The IMAP session may or may not have been allocated/setup at this
1666*6236dae4SAndroid Build Coastguard Worker point! */
1667*6236dae4SAndroid Build Coastguard Worker if(!dead_connection && conn->bits.protoconnstart) {
1668*6236dae4SAndroid Build Coastguard Worker if(!imap_perform_logout(data))
1669*6236dae4SAndroid Build Coastguard Worker (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */
1670*6236dae4SAndroid Build Coastguard Worker }
1671*6236dae4SAndroid Build Coastguard Worker
1672*6236dae4SAndroid Build Coastguard Worker /* Disconnect from the server */
1673*6236dae4SAndroid Build Coastguard Worker Curl_pp_disconnect(&imapc->pp);
1674*6236dae4SAndroid Build Coastguard Worker Curl_dyn_free(&imapc->dyn);
1675*6236dae4SAndroid Build Coastguard Worker
1676*6236dae4SAndroid Build Coastguard Worker /* Cleanup the SASL module */
1677*6236dae4SAndroid Build Coastguard Worker Curl_sasl_cleanup(conn, imapc->sasl.authused);
1678*6236dae4SAndroid Build Coastguard Worker
1679*6236dae4SAndroid Build Coastguard Worker /* Cleanup our connection based variables */
1680*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imapc->mailbox);
1681*6236dae4SAndroid Build Coastguard Worker Curl_safefree(imapc->mailbox_uidvalidity);
1682*6236dae4SAndroid Build Coastguard Worker
1683*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1684*6236dae4SAndroid Build Coastguard Worker }
1685*6236dae4SAndroid Build Coastguard Worker
1686*6236dae4SAndroid Build Coastguard Worker /* Call this when the DO phase has completed */
imap_dophase_done(struct Curl_easy * data,bool connected)1687*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_dophase_done(struct Curl_easy *data, bool connected)
1688*6236dae4SAndroid Build Coastguard Worker {
1689*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
1690*6236dae4SAndroid Build Coastguard Worker
1691*6236dae4SAndroid Build Coastguard Worker (void)connected;
1692*6236dae4SAndroid Build Coastguard Worker
1693*6236dae4SAndroid Build Coastguard Worker if(imap->transfer != PPTRANSFER_BODY)
1694*6236dae4SAndroid Build Coastguard Worker /* no data to transfer */
1695*6236dae4SAndroid Build Coastguard Worker Curl_xfer_setup_nop(data);
1696*6236dae4SAndroid Build Coastguard Worker
1697*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1698*6236dae4SAndroid Build Coastguard Worker }
1699*6236dae4SAndroid Build Coastguard Worker
1700*6236dae4SAndroid Build Coastguard Worker /* Called from multi.c while DOing */
imap_doing(struct Curl_easy * data,bool * dophase_done)1701*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done)
1702*6236dae4SAndroid Build Coastguard Worker {
1703*6236dae4SAndroid Build Coastguard Worker CURLcode result = imap_multi_statemach(data, dophase_done);
1704*6236dae4SAndroid Build Coastguard Worker
1705*6236dae4SAndroid Build Coastguard Worker if(result)
1706*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "DO phase failed"));
1707*6236dae4SAndroid Build Coastguard Worker else if(*dophase_done) {
1708*6236dae4SAndroid Build Coastguard Worker result = imap_dophase_done(data, FALSE /* not connected */);
1709*6236dae4SAndroid Build Coastguard Worker
1710*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "DO phase is complete"));
1711*6236dae4SAndroid Build Coastguard Worker }
1712*6236dae4SAndroid Build Coastguard Worker
1713*6236dae4SAndroid Build Coastguard Worker return result;
1714*6236dae4SAndroid Build Coastguard Worker }
1715*6236dae4SAndroid Build Coastguard Worker
1716*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1717*6236dae4SAndroid Build Coastguard Worker *
1718*6236dae4SAndroid Build Coastguard Worker * imap_regular_transfer()
1719*6236dae4SAndroid Build Coastguard Worker *
1720*6236dae4SAndroid Build Coastguard Worker * The input argument is already checked for validity.
1721*6236dae4SAndroid Build Coastguard Worker *
1722*6236dae4SAndroid Build Coastguard Worker * Performs all commands done before a regular transfer between a local and a
1723*6236dae4SAndroid Build Coastguard Worker * remote host.
1724*6236dae4SAndroid Build Coastguard Worker */
imap_regular_transfer(struct Curl_easy * data,bool * dophase_done)1725*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_regular_transfer(struct Curl_easy *data,
1726*6236dae4SAndroid Build Coastguard Worker bool *dophase_done)
1727*6236dae4SAndroid Build Coastguard Worker {
1728*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1729*6236dae4SAndroid Build Coastguard Worker bool connected = FALSE;
1730*6236dae4SAndroid Build Coastguard Worker
1731*6236dae4SAndroid Build Coastguard Worker /* Make sure size is unknown at this point */
1732*6236dae4SAndroid Build Coastguard Worker data->req.size = -1;
1733*6236dae4SAndroid Build Coastguard Worker
1734*6236dae4SAndroid Build Coastguard Worker /* Set the progress data */
1735*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetUploadCounter(data, 0);
1736*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadCounter(data, 0);
1737*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetUploadSize(data, -1);
1738*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadSize(data, -1);
1739*6236dae4SAndroid Build Coastguard Worker
1740*6236dae4SAndroid Build Coastguard Worker /* Carry out the perform */
1741*6236dae4SAndroid Build Coastguard Worker result = imap_perform(data, &connected, dophase_done);
1742*6236dae4SAndroid Build Coastguard Worker
1743*6236dae4SAndroid Build Coastguard Worker /* Perform post DO phase operations if necessary */
1744*6236dae4SAndroid Build Coastguard Worker if(!result && *dophase_done)
1745*6236dae4SAndroid Build Coastguard Worker result = imap_dophase_done(data, connected);
1746*6236dae4SAndroid Build Coastguard Worker
1747*6236dae4SAndroid Build Coastguard Worker return result;
1748*6236dae4SAndroid Build Coastguard Worker }
1749*6236dae4SAndroid Build Coastguard Worker
imap_setup_connection(struct Curl_easy * data,struct connectdata * conn)1750*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_setup_connection(struct Curl_easy *data,
1751*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
1752*6236dae4SAndroid Build Coastguard Worker {
1753*6236dae4SAndroid Build Coastguard Worker /* Initialise the IMAP layer */
1754*6236dae4SAndroid Build Coastguard Worker CURLcode result = imap_init(data);
1755*6236dae4SAndroid Build Coastguard Worker if(result)
1756*6236dae4SAndroid Build Coastguard Worker return result;
1757*6236dae4SAndroid Build Coastguard Worker
1758*6236dae4SAndroid Build Coastguard Worker /* Clear the TLS upgraded flag */
1759*6236dae4SAndroid Build Coastguard Worker conn->bits.tls_upgraded = FALSE;
1760*6236dae4SAndroid Build Coastguard Worker
1761*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
1762*6236dae4SAndroid Build Coastguard Worker }
1763*6236dae4SAndroid Build Coastguard Worker
1764*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1765*6236dae4SAndroid Build Coastguard Worker *
1766*6236dae4SAndroid Build Coastguard Worker * imap_sendf()
1767*6236dae4SAndroid Build Coastguard Worker *
1768*6236dae4SAndroid Build Coastguard Worker * Sends the formatted string as an IMAP command to the server.
1769*6236dae4SAndroid Build Coastguard Worker *
1770*6236dae4SAndroid Build Coastguard Worker * Designed to never block.
1771*6236dae4SAndroid Build Coastguard Worker */
imap_sendf(struct Curl_easy * data,const char * fmt,...)1772*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
1773*6236dae4SAndroid Build Coastguard Worker {
1774*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1775*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &data->conn->proto.imapc;
1776*6236dae4SAndroid Build Coastguard Worker
1777*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(fmt);
1778*6236dae4SAndroid Build Coastguard Worker
1779*6236dae4SAndroid Build Coastguard Worker /* Calculate the tag based on the connection ID and command ID */
1780*6236dae4SAndroid Build Coastguard Worker msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
1781*6236dae4SAndroid Build Coastguard Worker 'A' + curlx_sltosi((long)(data->conn->connection_id % 26)),
1782*6236dae4SAndroid Build Coastguard Worker ++imapc->cmdid);
1783*6236dae4SAndroid Build Coastguard Worker
1784*6236dae4SAndroid Build Coastguard Worker /* start with a blank buffer */
1785*6236dae4SAndroid Build Coastguard Worker Curl_dyn_reset(&imapc->dyn);
1786*6236dae4SAndroid Build Coastguard Worker
1787*6236dae4SAndroid Build Coastguard Worker /* append tag + space + fmt */
1788*6236dae4SAndroid Build Coastguard Worker result = Curl_dyn_addf(&imapc->dyn, "%s %s", imapc->resptag, fmt);
1789*6236dae4SAndroid Build Coastguard Worker if(!result) {
1790*6236dae4SAndroid Build Coastguard Worker va_list ap;
1791*6236dae4SAndroid Build Coastguard Worker va_start(ap, fmt);
1792*6236dae4SAndroid Build Coastguard Worker #ifdef __clang__
1793*6236dae4SAndroid Build Coastguard Worker #pragma clang diagnostic push
1794*6236dae4SAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wformat-nonliteral"
1795*6236dae4SAndroid Build Coastguard Worker #endif
1796*6236dae4SAndroid Build Coastguard Worker result = Curl_pp_vsendf(data, &imapc->pp, Curl_dyn_ptr(&imapc->dyn), ap);
1797*6236dae4SAndroid Build Coastguard Worker #ifdef __clang__
1798*6236dae4SAndroid Build Coastguard Worker #pragma clang diagnostic pop
1799*6236dae4SAndroid Build Coastguard Worker #endif
1800*6236dae4SAndroid Build Coastguard Worker va_end(ap);
1801*6236dae4SAndroid Build Coastguard Worker }
1802*6236dae4SAndroid Build Coastguard Worker return result;
1803*6236dae4SAndroid Build Coastguard Worker }
1804*6236dae4SAndroid Build Coastguard Worker
1805*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1806*6236dae4SAndroid Build Coastguard Worker *
1807*6236dae4SAndroid Build Coastguard Worker * imap_atom()
1808*6236dae4SAndroid Build Coastguard Worker *
1809*6236dae4SAndroid Build Coastguard Worker * Checks the input string for characters that need escaping and returns an
1810*6236dae4SAndroid Build Coastguard Worker * atom ready for sending to the server.
1811*6236dae4SAndroid Build Coastguard Worker *
1812*6236dae4SAndroid Build Coastguard Worker * The returned string needs to be freed.
1813*6236dae4SAndroid Build Coastguard Worker *
1814*6236dae4SAndroid Build Coastguard Worker */
imap_atom(const char * str,bool escape_only)1815*6236dae4SAndroid Build Coastguard Worker static char *imap_atom(const char *str, bool escape_only)
1816*6236dae4SAndroid Build Coastguard Worker {
1817*6236dae4SAndroid Build Coastguard Worker struct dynbuf line;
1818*6236dae4SAndroid Build Coastguard Worker size_t nclean;
1819*6236dae4SAndroid Build Coastguard Worker size_t len;
1820*6236dae4SAndroid Build Coastguard Worker
1821*6236dae4SAndroid Build Coastguard Worker if(!str)
1822*6236dae4SAndroid Build Coastguard Worker return NULL;
1823*6236dae4SAndroid Build Coastguard Worker
1824*6236dae4SAndroid Build Coastguard Worker len = strlen(str);
1825*6236dae4SAndroid Build Coastguard Worker nclean = strcspn(str, "() {%*]\\\"");
1826*6236dae4SAndroid Build Coastguard Worker if(len == nclean)
1827*6236dae4SAndroid Build Coastguard Worker /* nothing to escape, return a strdup */
1828*6236dae4SAndroid Build Coastguard Worker return strdup(str);
1829*6236dae4SAndroid Build Coastguard Worker
1830*6236dae4SAndroid Build Coastguard Worker Curl_dyn_init(&line, 2000);
1831*6236dae4SAndroid Build Coastguard Worker
1832*6236dae4SAndroid Build Coastguard Worker if(!escape_only && Curl_dyn_addn(&line, "\"", 1))
1833*6236dae4SAndroid Build Coastguard Worker return NULL;
1834*6236dae4SAndroid Build Coastguard Worker
1835*6236dae4SAndroid Build Coastguard Worker while(*str) {
1836*6236dae4SAndroid Build Coastguard Worker if((*str == '\\' || *str == '"') &&
1837*6236dae4SAndroid Build Coastguard Worker Curl_dyn_addn(&line, "\\", 1))
1838*6236dae4SAndroid Build Coastguard Worker return NULL;
1839*6236dae4SAndroid Build Coastguard Worker if(Curl_dyn_addn(&line, str, 1))
1840*6236dae4SAndroid Build Coastguard Worker return NULL;
1841*6236dae4SAndroid Build Coastguard Worker str++;
1842*6236dae4SAndroid Build Coastguard Worker }
1843*6236dae4SAndroid Build Coastguard Worker
1844*6236dae4SAndroid Build Coastguard Worker if(!escape_only && Curl_dyn_addn(&line, "\"", 1))
1845*6236dae4SAndroid Build Coastguard Worker return NULL;
1846*6236dae4SAndroid Build Coastguard Worker
1847*6236dae4SAndroid Build Coastguard Worker return Curl_dyn_ptr(&line);
1848*6236dae4SAndroid Build Coastguard Worker }
1849*6236dae4SAndroid Build Coastguard Worker
1850*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1851*6236dae4SAndroid Build Coastguard Worker *
1852*6236dae4SAndroid Build Coastguard Worker * imap_is_bchar()
1853*6236dae4SAndroid Build Coastguard Worker *
1854*6236dae4SAndroid Build Coastguard Worker * Portable test of whether the specified char is a "bchar" as defined in the
1855*6236dae4SAndroid Build Coastguard Worker * grammar of RFC-5092.
1856*6236dae4SAndroid Build Coastguard Worker */
imap_is_bchar(char ch)1857*6236dae4SAndroid Build Coastguard Worker static bool imap_is_bchar(char ch)
1858*6236dae4SAndroid Build Coastguard Worker {
1859*6236dae4SAndroid Build Coastguard Worker /* Performing the alnum check with this macro is faster because of ASCII
1860*6236dae4SAndroid Build Coastguard Worker arithmetic */
1861*6236dae4SAndroid Build Coastguard Worker if(ISALNUM(ch))
1862*6236dae4SAndroid Build Coastguard Worker return TRUE;
1863*6236dae4SAndroid Build Coastguard Worker
1864*6236dae4SAndroid Build Coastguard Worker switch(ch) {
1865*6236dae4SAndroid Build Coastguard Worker /* bchar */
1866*6236dae4SAndroid Build Coastguard Worker case ':': case '@': case '/':
1867*6236dae4SAndroid Build Coastguard Worker /* bchar -> achar */
1868*6236dae4SAndroid Build Coastguard Worker case '&': case '=':
1869*6236dae4SAndroid Build Coastguard Worker /* bchar -> achar -> uchar -> unreserved (without alphanumeric) */
1870*6236dae4SAndroid Build Coastguard Worker case '-': case '.': case '_': case '~':
1871*6236dae4SAndroid Build Coastguard Worker /* bchar -> achar -> uchar -> sub-delims-sh */
1872*6236dae4SAndroid Build Coastguard Worker case '!': case '$': case '\'': case '(': case ')': case '*':
1873*6236dae4SAndroid Build Coastguard Worker case '+': case ',':
1874*6236dae4SAndroid Build Coastguard Worker /* bchar -> achar -> uchar -> pct-encoded */
1875*6236dae4SAndroid Build Coastguard Worker case '%': /* HEXDIG chars are already included above */
1876*6236dae4SAndroid Build Coastguard Worker return TRUE;
1877*6236dae4SAndroid Build Coastguard Worker
1878*6236dae4SAndroid Build Coastguard Worker default:
1879*6236dae4SAndroid Build Coastguard Worker return FALSE;
1880*6236dae4SAndroid Build Coastguard Worker }
1881*6236dae4SAndroid Build Coastguard Worker }
1882*6236dae4SAndroid Build Coastguard Worker
1883*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1884*6236dae4SAndroid Build Coastguard Worker *
1885*6236dae4SAndroid Build Coastguard Worker * imap_parse_url_options()
1886*6236dae4SAndroid Build Coastguard Worker *
1887*6236dae4SAndroid Build Coastguard Worker * Parse the URL login options.
1888*6236dae4SAndroid Build Coastguard Worker */
imap_parse_url_options(struct connectdata * conn)1889*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_parse_url_options(struct connectdata *conn)
1890*6236dae4SAndroid Build Coastguard Worker {
1891*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1892*6236dae4SAndroid Build Coastguard Worker struct imap_conn *imapc = &conn->proto.imapc;
1893*6236dae4SAndroid Build Coastguard Worker const char *ptr = conn->options;
1894*6236dae4SAndroid Build Coastguard Worker bool prefer_login = FALSE;
1895*6236dae4SAndroid Build Coastguard Worker
1896*6236dae4SAndroid Build Coastguard Worker while(!result && ptr && *ptr) {
1897*6236dae4SAndroid Build Coastguard Worker const char *key = ptr;
1898*6236dae4SAndroid Build Coastguard Worker const char *value;
1899*6236dae4SAndroid Build Coastguard Worker
1900*6236dae4SAndroid Build Coastguard Worker while(*ptr && *ptr != '=')
1901*6236dae4SAndroid Build Coastguard Worker ptr++;
1902*6236dae4SAndroid Build Coastguard Worker
1903*6236dae4SAndroid Build Coastguard Worker value = ptr + 1;
1904*6236dae4SAndroid Build Coastguard Worker
1905*6236dae4SAndroid Build Coastguard Worker while(*ptr && *ptr != ';')
1906*6236dae4SAndroid Build Coastguard Worker ptr++;
1907*6236dae4SAndroid Build Coastguard Worker
1908*6236dae4SAndroid Build Coastguard Worker if(strncasecompare(key, "AUTH=+LOGIN", 11)) {
1909*6236dae4SAndroid Build Coastguard Worker /* User prefers plaintext LOGIN over any SASL, including SASL LOGIN */
1910*6236dae4SAndroid Build Coastguard Worker prefer_login = TRUE;
1911*6236dae4SAndroid Build Coastguard Worker imapc->sasl.prefmech = SASL_AUTH_NONE;
1912*6236dae4SAndroid Build Coastguard Worker }
1913*6236dae4SAndroid Build Coastguard Worker else if(strncasecompare(key, "AUTH=", 5)) {
1914*6236dae4SAndroid Build Coastguard Worker prefer_login = FALSE;
1915*6236dae4SAndroid Build Coastguard Worker result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
1916*6236dae4SAndroid Build Coastguard Worker value, ptr - value);
1917*6236dae4SAndroid Build Coastguard Worker }
1918*6236dae4SAndroid Build Coastguard Worker else {
1919*6236dae4SAndroid Build Coastguard Worker prefer_login = FALSE;
1920*6236dae4SAndroid Build Coastguard Worker result = CURLE_URL_MALFORMAT;
1921*6236dae4SAndroid Build Coastguard Worker }
1922*6236dae4SAndroid Build Coastguard Worker
1923*6236dae4SAndroid Build Coastguard Worker if(*ptr == ';')
1924*6236dae4SAndroid Build Coastguard Worker ptr++;
1925*6236dae4SAndroid Build Coastguard Worker }
1926*6236dae4SAndroid Build Coastguard Worker
1927*6236dae4SAndroid Build Coastguard Worker if(prefer_login)
1928*6236dae4SAndroid Build Coastguard Worker imapc->preftype = IMAP_TYPE_CLEARTEXT;
1929*6236dae4SAndroid Build Coastguard Worker else {
1930*6236dae4SAndroid Build Coastguard Worker switch(imapc->sasl.prefmech) {
1931*6236dae4SAndroid Build Coastguard Worker case SASL_AUTH_NONE:
1932*6236dae4SAndroid Build Coastguard Worker imapc->preftype = IMAP_TYPE_NONE;
1933*6236dae4SAndroid Build Coastguard Worker break;
1934*6236dae4SAndroid Build Coastguard Worker case SASL_AUTH_DEFAULT:
1935*6236dae4SAndroid Build Coastguard Worker imapc->preftype = IMAP_TYPE_ANY;
1936*6236dae4SAndroid Build Coastguard Worker break;
1937*6236dae4SAndroid Build Coastguard Worker default:
1938*6236dae4SAndroid Build Coastguard Worker imapc->preftype = IMAP_TYPE_SASL;
1939*6236dae4SAndroid Build Coastguard Worker break;
1940*6236dae4SAndroid Build Coastguard Worker }
1941*6236dae4SAndroid Build Coastguard Worker }
1942*6236dae4SAndroid Build Coastguard Worker
1943*6236dae4SAndroid Build Coastguard Worker return result;
1944*6236dae4SAndroid Build Coastguard Worker }
1945*6236dae4SAndroid Build Coastguard Worker
1946*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1947*6236dae4SAndroid Build Coastguard Worker *
1948*6236dae4SAndroid Build Coastguard Worker * imap_parse_url_path()
1949*6236dae4SAndroid Build Coastguard Worker *
1950*6236dae4SAndroid Build Coastguard Worker * Parse the URL path into separate path components.
1951*6236dae4SAndroid Build Coastguard Worker *
1952*6236dae4SAndroid Build Coastguard Worker */
imap_parse_url_path(struct Curl_easy * data)1953*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_parse_url_path(struct Curl_easy *data)
1954*6236dae4SAndroid Build Coastguard Worker {
1955*6236dae4SAndroid Build Coastguard Worker /* The imap struct is already initialised in imap_connect() */
1956*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
1957*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
1958*6236dae4SAndroid Build Coastguard Worker const char *begin = &data->state.up.path[1]; /* skip leading slash */
1959*6236dae4SAndroid Build Coastguard Worker const char *ptr = begin;
1960*6236dae4SAndroid Build Coastguard Worker
1961*6236dae4SAndroid Build Coastguard Worker /* See how much of the URL is a valid path and decode it */
1962*6236dae4SAndroid Build Coastguard Worker while(imap_is_bchar(*ptr))
1963*6236dae4SAndroid Build Coastguard Worker ptr++;
1964*6236dae4SAndroid Build Coastguard Worker
1965*6236dae4SAndroid Build Coastguard Worker if(ptr != begin) {
1966*6236dae4SAndroid Build Coastguard Worker /* Remove the trailing slash if present */
1967*6236dae4SAndroid Build Coastguard Worker const char *end = ptr;
1968*6236dae4SAndroid Build Coastguard Worker if(end > begin && end[-1] == '/')
1969*6236dae4SAndroid Build Coastguard Worker end--;
1970*6236dae4SAndroid Build Coastguard Worker
1971*6236dae4SAndroid Build Coastguard Worker result = Curl_urldecode(begin, end - begin, &imap->mailbox, NULL,
1972*6236dae4SAndroid Build Coastguard Worker REJECT_CTRL);
1973*6236dae4SAndroid Build Coastguard Worker if(result)
1974*6236dae4SAndroid Build Coastguard Worker return result;
1975*6236dae4SAndroid Build Coastguard Worker }
1976*6236dae4SAndroid Build Coastguard Worker else
1977*6236dae4SAndroid Build Coastguard Worker imap->mailbox = NULL;
1978*6236dae4SAndroid Build Coastguard Worker
1979*6236dae4SAndroid Build Coastguard Worker /* There can be any number of parameters in the form ";NAME=VALUE" */
1980*6236dae4SAndroid Build Coastguard Worker while(*ptr == ';') {
1981*6236dae4SAndroid Build Coastguard Worker char *name;
1982*6236dae4SAndroid Build Coastguard Worker char *value;
1983*6236dae4SAndroid Build Coastguard Worker size_t valuelen;
1984*6236dae4SAndroid Build Coastguard Worker
1985*6236dae4SAndroid Build Coastguard Worker /* Find the length of the name parameter */
1986*6236dae4SAndroid Build Coastguard Worker begin = ++ptr;
1987*6236dae4SAndroid Build Coastguard Worker while(*ptr && *ptr != '=')
1988*6236dae4SAndroid Build Coastguard Worker ptr++;
1989*6236dae4SAndroid Build Coastguard Worker
1990*6236dae4SAndroid Build Coastguard Worker if(!*ptr)
1991*6236dae4SAndroid Build Coastguard Worker return CURLE_URL_MALFORMAT;
1992*6236dae4SAndroid Build Coastguard Worker
1993*6236dae4SAndroid Build Coastguard Worker /* Decode the name parameter */
1994*6236dae4SAndroid Build Coastguard Worker result = Curl_urldecode(begin, ptr - begin, &name, NULL,
1995*6236dae4SAndroid Build Coastguard Worker REJECT_CTRL);
1996*6236dae4SAndroid Build Coastguard Worker if(result)
1997*6236dae4SAndroid Build Coastguard Worker return result;
1998*6236dae4SAndroid Build Coastguard Worker
1999*6236dae4SAndroid Build Coastguard Worker /* Find the length of the value parameter */
2000*6236dae4SAndroid Build Coastguard Worker begin = ++ptr;
2001*6236dae4SAndroid Build Coastguard Worker while(imap_is_bchar(*ptr))
2002*6236dae4SAndroid Build Coastguard Worker ptr++;
2003*6236dae4SAndroid Build Coastguard Worker
2004*6236dae4SAndroid Build Coastguard Worker /* Decode the value parameter */
2005*6236dae4SAndroid Build Coastguard Worker result = Curl_urldecode(begin, ptr - begin, &value, &valuelen,
2006*6236dae4SAndroid Build Coastguard Worker REJECT_CTRL);
2007*6236dae4SAndroid Build Coastguard Worker if(result) {
2008*6236dae4SAndroid Build Coastguard Worker free(name);
2009*6236dae4SAndroid Build Coastguard Worker return result;
2010*6236dae4SAndroid Build Coastguard Worker }
2011*6236dae4SAndroid Build Coastguard Worker
2012*6236dae4SAndroid Build Coastguard Worker DEBUGF(infof(data, "IMAP URL parameter '%s' = '%s'", name, value));
2013*6236dae4SAndroid Build Coastguard Worker
2014*6236dae4SAndroid Build Coastguard Worker /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and
2015*6236dae4SAndroid Build Coastguard Worker PARTIAL) stripping of the trailing slash character if it is present.
2016*6236dae4SAndroid Build Coastguard Worker
2017*6236dae4SAndroid Build Coastguard Worker Note: Unknown parameters trigger a URL_MALFORMAT error. */
2018*6236dae4SAndroid Build Coastguard Worker if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) {
2019*6236dae4SAndroid Build Coastguard Worker if(valuelen > 0 && value[valuelen - 1] == '/')
2020*6236dae4SAndroid Build Coastguard Worker value[valuelen - 1] = '\0';
2021*6236dae4SAndroid Build Coastguard Worker
2022*6236dae4SAndroid Build Coastguard Worker imap->uidvalidity = value;
2023*6236dae4SAndroid Build Coastguard Worker value = NULL;
2024*6236dae4SAndroid Build Coastguard Worker }
2025*6236dae4SAndroid Build Coastguard Worker else if(strcasecompare(name, "UID") && !imap->uid) {
2026*6236dae4SAndroid Build Coastguard Worker if(valuelen > 0 && value[valuelen - 1] == '/')
2027*6236dae4SAndroid Build Coastguard Worker value[valuelen - 1] = '\0';
2028*6236dae4SAndroid Build Coastguard Worker
2029*6236dae4SAndroid Build Coastguard Worker imap->uid = value;
2030*6236dae4SAndroid Build Coastguard Worker value = NULL;
2031*6236dae4SAndroid Build Coastguard Worker }
2032*6236dae4SAndroid Build Coastguard Worker else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) {
2033*6236dae4SAndroid Build Coastguard Worker if(valuelen > 0 && value[valuelen - 1] == '/')
2034*6236dae4SAndroid Build Coastguard Worker value[valuelen - 1] = '\0';
2035*6236dae4SAndroid Build Coastguard Worker
2036*6236dae4SAndroid Build Coastguard Worker imap->mindex = value;
2037*6236dae4SAndroid Build Coastguard Worker value = NULL;
2038*6236dae4SAndroid Build Coastguard Worker }
2039*6236dae4SAndroid Build Coastguard Worker else if(strcasecompare(name, "SECTION") && !imap->section) {
2040*6236dae4SAndroid Build Coastguard Worker if(valuelen > 0 && value[valuelen - 1] == '/')
2041*6236dae4SAndroid Build Coastguard Worker value[valuelen - 1] = '\0';
2042*6236dae4SAndroid Build Coastguard Worker
2043*6236dae4SAndroid Build Coastguard Worker imap->section = value;
2044*6236dae4SAndroid Build Coastguard Worker value = NULL;
2045*6236dae4SAndroid Build Coastguard Worker }
2046*6236dae4SAndroid Build Coastguard Worker else if(strcasecompare(name, "PARTIAL") && !imap->partial) {
2047*6236dae4SAndroid Build Coastguard Worker if(valuelen > 0 && value[valuelen - 1] == '/')
2048*6236dae4SAndroid Build Coastguard Worker value[valuelen - 1] = '\0';
2049*6236dae4SAndroid Build Coastguard Worker
2050*6236dae4SAndroid Build Coastguard Worker imap->partial = value;
2051*6236dae4SAndroid Build Coastguard Worker value = NULL;
2052*6236dae4SAndroid Build Coastguard Worker }
2053*6236dae4SAndroid Build Coastguard Worker else {
2054*6236dae4SAndroid Build Coastguard Worker free(name);
2055*6236dae4SAndroid Build Coastguard Worker free(value);
2056*6236dae4SAndroid Build Coastguard Worker
2057*6236dae4SAndroid Build Coastguard Worker return CURLE_URL_MALFORMAT;
2058*6236dae4SAndroid Build Coastguard Worker }
2059*6236dae4SAndroid Build Coastguard Worker
2060*6236dae4SAndroid Build Coastguard Worker free(name);
2061*6236dae4SAndroid Build Coastguard Worker free(value);
2062*6236dae4SAndroid Build Coastguard Worker }
2063*6236dae4SAndroid Build Coastguard Worker
2064*6236dae4SAndroid Build Coastguard Worker /* Does the URL contain a query parameter? Only valid when we have a mailbox
2065*6236dae4SAndroid Build Coastguard Worker and no UID as per RFC-5092 */
2066*6236dae4SAndroid Build Coastguard Worker if(imap->mailbox && !imap->uid && !imap->mindex) {
2067*6236dae4SAndroid Build Coastguard Worker /* Get the query parameter, URL decoded */
2068*6236dae4SAndroid Build Coastguard Worker (void)curl_url_get(data->state.uh, CURLUPART_QUERY, &imap->query,
2069*6236dae4SAndroid Build Coastguard Worker CURLU_URLDECODE);
2070*6236dae4SAndroid Build Coastguard Worker }
2071*6236dae4SAndroid Build Coastguard Worker
2072*6236dae4SAndroid Build Coastguard Worker /* Any extra stuff at the end of the URL is an error */
2073*6236dae4SAndroid Build Coastguard Worker if(*ptr)
2074*6236dae4SAndroid Build Coastguard Worker return CURLE_URL_MALFORMAT;
2075*6236dae4SAndroid Build Coastguard Worker
2076*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
2077*6236dae4SAndroid Build Coastguard Worker }
2078*6236dae4SAndroid Build Coastguard Worker
2079*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
2080*6236dae4SAndroid Build Coastguard Worker *
2081*6236dae4SAndroid Build Coastguard Worker * imap_parse_custom_request()
2082*6236dae4SAndroid Build Coastguard Worker *
2083*6236dae4SAndroid Build Coastguard Worker * Parse the custom request.
2084*6236dae4SAndroid Build Coastguard Worker */
imap_parse_custom_request(struct Curl_easy * data)2085*6236dae4SAndroid Build Coastguard Worker static CURLcode imap_parse_custom_request(struct Curl_easy *data)
2086*6236dae4SAndroid Build Coastguard Worker {
2087*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
2088*6236dae4SAndroid Build Coastguard Worker struct IMAP *imap = data->req.p.imap;
2089*6236dae4SAndroid Build Coastguard Worker const char *custom = data->set.str[STRING_CUSTOMREQUEST];
2090*6236dae4SAndroid Build Coastguard Worker
2091*6236dae4SAndroid Build Coastguard Worker if(custom) {
2092*6236dae4SAndroid Build Coastguard Worker /* URL decode the custom request */
2093*6236dae4SAndroid Build Coastguard Worker result = Curl_urldecode(custom, 0, &imap->custom, NULL, REJECT_CTRL);
2094*6236dae4SAndroid Build Coastguard Worker
2095*6236dae4SAndroid Build Coastguard Worker /* Extract the parameters if specified */
2096*6236dae4SAndroid Build Coastguard Worker if(!result) {
2097*6236dae4SAndroid Build Coastguard Worker const char *params = imap->custom;
2098*6236dae4SAndroid Build Coastguard Worker
2099*6236dae4SAndroid Build Coastguard Worker while(*params && *params != ' ')
2100*6236dae4SAndroid Build Coastguard Worker params++;
2101*6236dae4SAndroid Build Coastguard Worker
2102*6236dae4SAndroid Build Coastguard Worker if(*params) {
2103*6236dae4SAndroid Build Coastguard Worker imap->custom_params = strdup(params);
2104*6236dae4SAndroid Build Coastguard Worker imap->custom[params - imap->custom] = '\0';
2105*6236dae4SAndroid Build Coastguard Worker
2106*6236dae4SAndroid Build Coastguard Worker if(!imap->custom_params)
2107*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
2108*6236dae4SAndroid Build Coastguard Worker }
2109*6236dae4SAndroid Build Coastguard Worker }
2110*6236dae4SAndroid Build Coastguard Worker }
2111*6236dae4SAndroid Build Coastguard Worker
2112*6236dae4SAndroid Build Coastguard Worker return result;
2113*6236dae4SAndroid Build Coastguard Worker }
2114*6236dae4SAndroid Build Coastguard Worker
2115*6236dae4SAndroid Build Coastguard Worker #endif /* CURL_DISABLE_IMAP */
2116