xref: /aosp_15_r20/external/curl/lib/imap.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
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