xref: /aosp_15_r20/external/curl/lib/pop3.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  * RFC1734 POP3 Authentication
24*6236dae4SAndroid Build Coastguard Worker  * RFC1939 POP3 protocol
25*6236dae4SAndroid Build Coastguard Worker  * RFC2195 CRAM-MD5 authentication
26*6236dae4SAndroid Build Coastguard Worker  * RFC2384 POP URL Scheme
27*6236dae4SAndroid Build Coastguard Worker  * RFC2449 POP3 Extension Mechanism
28*6236dae4SAndroid Build Coastguard Worker  * RFC2595 Using TLS with IMAP, POP3 and ACAP
29*6236dae4SAndroid Build Coastguard Worker  * RFC2831 DIGEST-MD5 authentication
30*6236dae4SAndroid Build Coastguard Worker  * RFC4422 Simple Authentication and Security Layer (SASL)
31*6236dae4SAndroid Build Coastguard Worker  * RFC4616 PLAIN authentication
32*6236dae4SAndroid Build Coastguard Worker  * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
33*6236dae4SAndroid Build Coastguard Worker  * RFC5034 POP3 SASL Authentication Mechanism
34*6236dae4SAndroid Build Coastguard Worker  * RFC6749 OAuth 2.0 Authorization Framework
35*6236dae4SAndroid Build Coastguard Worker  * RFC8314 Use of TLS for Email Submission and Access
36*6236dae4SAndroid Build Coastguard Worker  * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
37*6236dae4SAndroid Build Coastguard Worker  *
38*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
39*6236dae4SAndroid Build Coastguard Worker 
40*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
41*6236dae4SAndroid Build Coastguard Worker 
42*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_POP3
43*6236dae4SAndroid Build Coastguard Worker 
44*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_IN_H
45*6236dae4SAndroid Build Coastguard Worker #include <netinet/in.h>
46*6236dae4SAndroid Build Coastguard Worker #endif
47*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_ARPA_INET_H
48*6236dae4SAndroid Build Coastguard Worker #include <arpa/inet.h>
49*6236dae4SAndroid Build Coastguard Worker #endif
50*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETDB_H
51*6236dae4SAndroid Build Coastguard Worker #include <netdb.h>
52*6236dae4SAndroid Build Coastguard Worker #endif
53*6236dae4SAndroid Build Coastguard Worker #ifdef __VMS
54*6236dae4SAndroid Build Coastguard Worker #include <in.h>
55*6236dae4SAndroid Build Coastguard Worker #include <inet.h>
56*6236dae4SAndroid Build Coastguard Worker #endif
57*6236dae4SAndroid Build Coastguard Worker 
58*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
59*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
60*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
61*6236dae4SAndroid Build Coastguard Worker #include "hostip.h"
62*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
63*6236dae4SAndroid Build Coastguard Worker #include "transfer.h"
64*6236dae4SAndroid Build Coastguard Worker #include "escape.h"
65*6236dae4SAndroid Build Coastguard Worker #include "http.h" /* for HTTP proxy tunnel stuff */
66*6236dae4SAndroid Build Coastguard Worker #include "socks.h"
67*6236dae4SAndroid Build Coastguard Worker #include "pop3.h"
68*6236dae4SAndroid Build Coastguard Worker #include "strtoofft.h"
69*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
70*6236dae4SAndroid Build Coastguard Worker #include "vtls/vtls.h"
71*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
72*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
73*6236dae4SAndroid Build Coastguard Worker #include "select.h"
74*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
75*6236dae4SAndroid Build Coastguard Worker #include "url.h"
76*6236dae4SAndroid Build Coastguard Worker #include "bufref.h"
77*6236dae4SAndroid Build Coastguard Worker #include "curl_sasl.h"
78*6236dae4SAndroid Build Coastguard Worker #include "curl_md5.h"
79*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
80*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
81*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
82*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
83*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
84*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
85*6236dae4SAndroid Build Coastguard Worker 
86*6236dae4SAndroid Build Coastguard Worker #ifndef ARRAYSIZE
87*6236dae4SAndroid Build Coastguard Worker #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
88*6236dae4SAndroid Build Coastguard Worker #endif
89*6236dae4SAndroid Build Coastguard Worker 
90*6236dae4SAndroid Build Coastguard Worker /* Local API functions */
91*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_regular_transfer(struct Curl_easy *data, bool *done);
92*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_do(struct Curl_easy *data, bool *done);
93*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_done(struct Curl_easy *data, CURLcode status,
94*6236dae4SAndroid Build Coastguard Worker                           bool premature);
95*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_connect(struct Curl_easy *data, bool *done);
96*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_disconnect(struct Curl_easy *data,
97*6236dae4SAndroid Build Coastguard Worker                                 struct connectdata *conn, bool dead);
98*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done);
99*6236dae4SAndroid Build Coastguard Worker static int pop3_getsock(struct Curl_easy *data,
100*6236dae4SAndroid Build Coastguard Worker                         struct connectdata *conn, curl_socket_t *socks);
101*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done);
102*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_setup_connection(struct Curl_easy *data,
103*6236dae4SAndroid Build Coastguard Worker                                       struct connectdata *conn);
104*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_parse_url_options(struct connectdata *conn);
105*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_parse_url_path(struct Curl_easy *data);
106*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_parse_custom_request(struct Curl_easy *data);
107*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform_auth(struct Curl_easy *data, const char *mech,
108*6236dae4SAndroid Build Coastguard Worker                                   const struct bufref *initresp);
109*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech,
110*6236dae4SAndroid Build Coastguard Worker                                    const struct bufref *resp);
111*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech);
112*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out);
113*6236dae4SAndroid Build Coastguard Worker 
114*6236dae4SAndroid Build Coastguard Worker /* This function scans the body after the end-of-body and writes everything
115*6236dae4SAndroid Build Coastguard Worker  * until the end is found */
116*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_write(struct Curl_easy *data,
117*6236dae4SAndroid Build Coastguard Worker                            const char *str, size_t nread, bool is_eos);
118*6236dae4SAndroid Build Coastguard Worker 
119*6236dae4SAndroid Build Coastguard Worker /*
120*6236dae4SAndroid Build Coastguard Worker  * POP3 protocol handler.
121*6236dae4SAndroid Build Coastguard Worker  */
122*6236dae4SAndroid Build Coastguard Worker 
123*6236dae4SAndroid Build Coastguard Worker const struct Curl_handler Curl_handler_pop3 = {
124*6236dae4SAndroid Build Coastguard Worker   "pop3",                           /* scheme */
125*6236dae4SAndroid Build Coastguard Worker   pop3_setup_connection,            /* setup_connection */
126*6236dae4SAndroid Build Coastguard Worker   pop3_do,                          /* do_it */
127*6236dae4SAndroid Build Coastguard Worker   pop3_done,                        /* done */
128*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* do_more */
129*6236dae4SAndroid Build Coastguard Worker   pop3_connect,                     /* connect_it */
130*6236dae4SAndroid Build Coastguard Worker   pop3_multi_statemach,             /* connecting */
131*6236dae4SAndroid Build Coastguard Worker   pop3_doing,                       /* doing */
132*6236dae4SAndroid Build Coastguard Worker   pop3_getsock,                     /* proto_getsock */
133*6236dae4SAndroid Build Coastguard Worker   pop3_getsock,                     /* doing_getsock */
134*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* domore_getsock */
135*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* perform_getsock */
136*6236dae4SAndroid Build Coastguard Worker   pop3_disconnect,                  /* disconnect */
137*6236dae4SAndroid Build Coastguard Worker   pop3_write,                       /* write_resp */
138*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* write_resp_hd */
139*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* connection_check */
140*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* attach connection */
141*6236dae4SAndroid Build Coastguard Worker   PORT_POP3,                        /* defport */
142*6236dae4SAndroid Build Coastguard Worker   CURLPROTO_POP3,                   /* protocol */
143*6236dae4SAndroid Build Coastguard Worker   CURLPROTO_POP3,                   /* family */
144*6236dae4SAndroid Build Coastguard Worker   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
145*6236dae4SAndroid Build Coastguard Worker   PROTOPT_URLOPTIONS
146*6236dae4SAndroid Build Coastguard Worker };
147*6236dae4SAndroid Build Coastguard Worker 
148*6236dae4SAndroid Build Coastguard Worker #ifdef USE_SSL
149*6236dae4SAndroid Build Coastguard Worker /*
150*6236dae4SAndroid Build Coastguard Worker  * POP3S protocol handler.
151*6236dae4SAndroid Build Coastguard Worker  */
152*6236dae4SAndroid Build Coastguard Worker 
153*6236dae4SAndroid Build Coastguard Worker const struct Curl_handler Curl_handler_pop3s = {
154*6236dae4SAndroid Build Coastguard Worker   "pop3s",                          /* scheme */
155*6236dae4SAndroid Build Coastguard Worker   pop3_setup_connection,            /* setup_connection */
156*6236dae4SAndroid Build Coastguard Worker   pop3_do,                          /* do_it */
157*6236dae4SAndroid Build Coastguard Worker   pop3_done,                        /* done */
158*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* do_more */
159*6236dae4SAndroid Build Coastguard Worker   pop3_connect,                     /* connect_it */
160*6236dae4SAndroid Build Coastguard Worker   pop3_multi_statemach,             /* connecting */
161*6236dae4SAndroid Build Coastguard Worker   pop3_doing,                       /* doing */
162*6236dae4SAndroid Build Coastguard Worker   pop3_getsock,                     /* proto_getsock */
163*6236dae4SAndroid Build Coastguard Worker   pop3_getsock,                     /* doing_getsock */
164*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* domore_getsock */
165*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* perform_getsock */
166*6236dae4SAndroid Build Coastguard Worker   pop3_disconnect,                  /* disconnect */
167*6236dae4SAndroid Build Coastguard Worker   pop3_write,                       /* write_resp */
168*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* write_resp_hd */
169*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* connection_check */
170*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                        /* attach connection */
171*6236dae4SAndroid Build Coastguard Worker   PORT_POP3S,                       /* defport */
172*6236dae4SAndroid Build Coastguard Worker   CURLPROTO_POP3S,                  /* protocol */
173*6236dae4SAndroid Build Coastguard Worker   CURLPROTO_POP3,                   /* family */
174*6236dae4SAndroid Build Coastguard Worker   PROTOPT_CLOSEACTION | PROTOPT_SSL
175*6236dae4SAndroid Build Coastguard Worker   | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
176*6236dae4SAndroid Build Coastguard Worker };
177*6236dae4SAndroid Build Coastguard Worker #endif
178*6236dae4SAndroid Build Coastguard Worker 
179*6236dae4SAndroid Build Coastguard Worker /* SASL parameters for the pop3 protocol */
180*6236dae4SAndroid Build Coastguard Worker static const struct SASLproto saslpop3 = {
181*6236dae4SAndroid Build Coastguard Worker   "pop",                /* The service name */
182*6236dae4SAndroid Build Coastguard Worker   pop3_perform_auth,    /* Send authentication command */
183*6236dae4SAndroid Build Coastguard Worker   pop3_continue_auth,   /* Send authentication continuation */
184*6236dae4SAndroid Build Coastguard Worker   pop3_cancel_auth,     /* Send authentication cancellation */
185*6236dae4SAndroid Build Coastguard Worker   pop3_get_message,     /* Get SASL response message */
186*6236dae4SAndroid Build Coastguard Worker   255 - 8,              /* Max line len - strlen("AUTH ") - 1 space - crlf */
187*6236dae4SAndroid Build Coastguard Worker   '*',                  /* Code received when continuation is expected */
188*6236dae4SAndroid Build Coastguard Worker   '+',                  /* 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 #ifdef USE_SSL
pop3_to_pop3s(struct connectdata * conn)194*6236dae4SAndroid Build Coastguard Worker static void pop3_to_pop3s(struct connectdata *conn)
195*6236dae4SAndroid Build Coastguard Worker {
196*6236dae4SAndroid Build Coastguard Worker   /* Change the connection handler */
197*6236dae4SAndroid Build Coastguard Worker   conn->handler = &Curl_handler_pop3s;
198*6236dae4SAndroid Build Coastguard Worker 
199*6236dae4SAndroid Build Coastguard Worker   /* Set the connection's upgraded to TLS flag */
200*6236dae4SAndroid Build Coastguard Worker   conn->bits.tls_upgraded = TRUE;
201*6236dae4SAndroid Build Coastguard Worker }
202*6236dae4SAndroid Build Coastguard Worker #else
203*6236dae4SAndroid Build Coastguard Worker #define pop3_to_pop3s(x) Curl_nop_stmt
204*6236dae4SAndroid Build Coastguard Worker #endif
205*6236dae4SAndroid Build Coastguard Worker 
206*6236dae4SAndroid Build Coastguard Worker struct pop3_cmd {
207*6236dae4SAndroid Build Coastguard Worker   const char *name;
208*6236dae4SAndroid Build Coastguard Worker   unsigned short nlen;
209*6236dae4SAndroid Build Coastguard Worker   BIT(multiline); /* response is multi-line with last '.' line */
210*6236dae4SAndroid Build Coastguard Worker   BIT(multiline_with_args); /* is multi-line when command has args */
211*6236dae4SAndroid Build Coastguard Worker };
212*6236dae4SAndroid Build Coastguard Worker 
213*6236dae4SAndroid Build Coastguard Worker static const struct pop3_cmd pop3cmds[] = {
214*6236dae4SAndroid Build Coastguard Worker   { "APOP", 4, FALSE, FALSE },
215*6236dae4SAndroid Build Coastguard Worker   { "AUTH", 4, FALSE, FALSE },
216*6236dae4SAndroid Build Coastguard Worker   { "CAPA", 4, TRUE, TRUE },
217*6236dae4SAndroid Build Coastguard Worker   { "DELE", 4, FALSE, FALSE },
218*6236dae4SAndroid Build Coastguard Worker   { "LIST", 4, TRUE, FALSE },
219*6236dae4SAndroid Build Coastguard Worker   { "MSG",  3, TRUE, TRUE },
220*6236dae4SAndroid Build Coastguard Worker   { "NOOP", 4, FALSE, FALSE },
221*6236dae4SAndroid Build Coastguard Worker   { "PASS", 4, FALSE, FALSE },
222*6236dae4SAndroid Build Coastguard Worker   { "QUIT", 4, FALSE, FALSE },
223*6236dae4SAndroid Build Coastguard Worker   { "RETR", 4, TRUE, TRUE },
224*6236dae4SAndroid Build Coastguard Worker   { "RSET", 4, FALSE, FALSE },
225*6236dae4SAndroid Build Coastguard Worker   { "STAT", 4, FALSE, FALSE },
226*6236dae4SAndroid Build Coastguard Worker   { "STLS", 4, FALSE, FALSE },
227*6236dae4SAndroid Build Coastguard Worker   { "TOP",  3, TRUE, TRUE },
228*6236dae4SAndroid Build Coastguard Worker   { "UIDL", 4, TRUE, FALSE },
229*6236dae4SAndroid Build Coastguard Worker   { "USER", 4, FALSE, FALSE },
230*6236dae4SAndroid Build Coastguard Worker   { "UTF8", 4, FALSE, FALSE },
231*6236dae4SAndroid Build Coastguard Worker   { "XTND", 4, TRUE, TRUE },
232*6236dae4SAndroid Build Coastguard Worker };
233*6236dae4SAndroid Build Coastguard Worker 
234*6236dae4SAndroid Build Coastguard Worker /* Return iff a command is defined as "multi-line" (RFC 1939),
235*6236dae4SAndroid Build Coastguard Worker  * has a response terminated by a last line with a '.'.
236*6236dae4SAndroid Build Coastguard Worker  */
pop3_is_multiline(const char * cmdline)237*6236dae4SAndroid Build Coastguard Worker static bool pop3_is_multiline(const char *cmdline)
238*6236dae4SAndroid Build Coastguard Worker {
239*6236dae4SAndroid Build Coastguard Worker   size_t i;
240*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < ARRAYSIZE(pop3cmds); ++i) {
241*6236dae4SAndroid Build Coastguard Worker     if(strncasecompare(pop3cmds[i].name, cmdline, pop3cmds[i].nlen)) {
242*6236dae4SAndroid Build Coastguard Worker       if(!cmdline[pop3cmds[i].nlen])
243*6236dae4SAndroid Build Coastguard Worker         return pop3cmds[i].multiline;
244*6236dae4SAndroid Build Coastguard Worker       else if(cmdline[pop3cmds[i].nlen] == ' ')
245*6236dae4SAndroid Build Coastguard Worker         return pop3cmds[i].multiline_with_args;
246*6236dae4SAndroid Build Coastguard Worker     }
247*6236dae4SAndroid Build Coastguard Worker   }
248*6236dae4SAndroid Build Coastguard Worker   /* Unknown command, assume multi-line for backward compatibility with
249*6236dae4SAndroid Build Coastguard Worker    * earlier curl versions that only could do multi-line responses. */
250*6236dae4SAndroid Build Coastguard Worker   return TRUE;
251*6236dae4SAndroid Build Coastguard Worker }
252*6236dae4SAndroid Build Coastguard Worker 
253*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
254*6236dae4SAndroid Build Coastguard Worker  *
255*6236dae4SAndroid Build Coastguard Worker  * pop3_endofresp()
256*6236dae4SAndroid Build Coastguard Worker  *
257*6236dae4SAndroid Build Coastguard Worker  * Checks for an ending POP3 status code at the start of the given string, but
258*6236dae4SAndroid Build Coastguard Worker  * also detects the APOP timestamp from the server greeting and various
259*6236dae4SAndroid Build Coastguard Worker  * capabilities from the CAPA response including the supported authentication
260*6236dae4SAndroid Build Coastguard Worker  * types and allowed SASL mechanisms.
261*6236dae4SAndroid Build Coastguard Worker  */
pop3_endofresp(struct Curl_easy * data,struct connectdata * conn,char * line,size_t len,int * resp)262*6236dae4SAndroid Build Coastguard Worker static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn,
263*6236dae4SAndroid Build Coastguard Worker                            char *line, size_t len, int *resp)
264*6236dae4SAndroid Build Coastguard Worker {
265*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
266*6236dae4SAndroid Build Coastguard Worker   (void)data;
267*6236dae4SAndroid Build Coastguard Worker 
268*6236dae4SAndroid Build Coastguard Worker   /* Do we have an error response? */
269*6236dae4SAndroid Build Coastguard Worker   if(len >= 4 && !memcmp("-ERR", line, 4)) {
270*6236dae4SAndroid Build Coastguard Worker     *resp = '-';
271*6236dae4SAndroid Build Coastguard Worker 
272*6236dae4SAndroid Build Coastguard Worker     return TRUE;
273*6236dae4SAndroid Build Coastguard Worker   }
274*6236dae4SAndroid Build Coastguard Worker 
275*6236dae4SAndroid Build Coastguard Worker   /* Are we processing CAPA command responses? */
276*6236dae4SAndroid Build Coastguard Worker   if(pop3c->state == POP3_CAPA) {
277*6236dae4SAndroid Build Coastguard Worker     /* Do we have the terminating line? */
278*6236dae4SAndroid Build Coastguard Worker     if(len >= 1 && line[0] == '.')
279*6236dae4SAndroid Build Coastguard Worker       /* Treat the response as a success */
280*6236dae4SAndroid Build Coastguard Worker       *resp = '+';
281*6236dae4SAndroid Build Coastguard Worker     else
282*6236dae4SAndroid Build Coastguard Worker       /* Treat the response as an untagged continuation */
283*6236dae4SAndroid Build Coastguard Worker       *resp = '*';
284*6236dae4SAndroid Build Coastguard Worker 
285*6236dae4SAndroid Build Coastguard Worker     return TRUE;
286*6236dae4SAndroid Build Coastguard Worker   }
287*6236dae4SAndroid Build Coastguard Worker 
288*6236dae4SAndroid Build Coastguard Worker   /* Do we have a success response? */
289*6236dae4SAndroid Build Coastguard Worker   if(len >= 3 && !memcmp("+OK", line, 3)) {
290*6236dae4SAndroid Build Coastguard Worker     *resp = '+';
291*6236dae4SAndroid Build Coastguard Worker 
292*6236dae4SAndroid Build Coastguard Worker     return TRUE;
293*6236dae4SAndroid Build Coastguard Worker   }
294*6236dae4SAndroid Build Coastguard Worker 
295*6236dae4SAndroid Build Coastguard Worker   /* Do we have a continuation response? */
296*6236dae4SAndroid Build Coastguard Worker   if(len >= 1 && line[0] == '+') {
297*6236dae4SAndroid Build Coastguard Worker     *resp = '*';
298*6236dae4SAndroid Build Coastguard Worker 
299*6236dae4SAndroid Build Coastguard Worker     return TRUE;
300*6236dae4SAndroid Build Coastguard Worker   }
301*6236dae4SAndroid Build Coastguard Worker 
302*6236dae4SAndroid Build Coastguard Worker   return FALSE; /* Nothing for us */
303*6236dae4SAndroid Build Coastguard Worker }
304*6236dae4SAndroid Build Coastguard Worker 
305*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
306*6236dae4SAndroid Build Coastguard Worker  *
307*6236dae4SAndroid Build Coastguard Worker  * pop3_get_message()
308*6236dae4SAndroid Build Coastguard Worker  *
309*6236dae4SAndroid Build Coastguard Worker  * Gets the authentication message from the response buffer.
310*6236dae4SAndroid Build Coastguard Worker  */
pop3_get_message(struct Curl_easy * data,struct bufref * out)311*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out)
312*6236dae4SAndroid Build Coastguard Worker {
313*6236dae4SAndroid Build Coastguard Worker   char *message = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
314*6236dae4SAndroid Build Coastguard Worker   size_t len = data->conn->proto.pop3c.pp.nfinal;
315*6236dae4SAndroid Build Coastguard Worker 
316*6236dae4SAndroid Build Coastguard Worker   if(len > 2) {
317*6236dae4SAndroid Build Coastguard Worker     /* Find the start of the message */
318*6236dae4SAndroid Build Coastguard Worker     len -= 2;
319*6236dae4SAndroid Build Coastguard Worker     for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
320*6236dae4SAndroid Build Coastguard Worker       ;
321*6236dae4SAndroid Build Coastguard Worker 
322*6236dae4SAndroid Build Coastguard Worker     /* Find the end of the message */
323*6236dae4SAndroid Build Coastguard Worker     while(len--)
324*6236dae4SAndroid Build Coastguard Worker       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
325*6236dae4SAndroid Build Coastguard Worker          message[len] != '\t')
326*6236dae4SAndroid Build Coastguard Worker         break;
327*6236dae4SAndroid Build Coastguard Worker 
328*6236dae4SAndroid Build Coastguard Worker     /* Terminate the message */
329*6236dae4SAndroid Build Coastguard Worker     message[++len] = '\0';
330*6236dae4SAndroid Build Coastguard Worker     Curl_bufref_set(out, message, len, NULL);
331*6236dae4SAndroid Build Coastguard Worker   }
332*6236dae4SAndroid Build Coastguard Worker   else
333*6236dae4SAndroid Build Coastguard Worker     /* junk input => zero length output */
334*6236dae4SAndroid Build Coastguard Worker     Curl_bufref_set(out, "", 0, NULL);
335*6236dae4SAndroid Build Coastguard Worker 
336*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
337*6236dae4SAndroid Build Coastguard Worker }
338*6236dae4SAndroid Build Coastguard Worker 
339*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
340*6236dae4SAndroid Build Coastguard Worker  *
341*6236dae4SAndroid Build Coastguard Worker  * pop3_state()
342*6236dae4SAndroid Build Coastguard Worker  *
343*6236dae4SAndroid Build Coastguard Worker  * This is the ONLY way to change POP3 state!
344*6236dae4SAndroid Build Coastguard Worker  */
pop3_state(struct Curl_easy * data,pop3state newstate)345*6236dae4SAndroid Build Coastguard Worker static void pop3_state(struct Curl_easy *data, pop3state newstate)
346*6236dae4SAndroid Build Coastguard Worker {
347*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &data->conn->proto.pop3c;
348*6236dae4SAndroid Build Coastguard Worker #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
349*6236dae4SAndroid Build Coastguard Worker   /* for debug purposes */
350*6236dae4SAndroid Build Coastguard Worker   static const char * const names[] = {
351*6236dae4SAndroid Build Coastguard Worker     "STOP",
352*6236dae4SAndroid Build Coastguard Worker     "SERVERGREET",
353*6236dae4SAndroid Build Coastguard Worker     "CAPA",
354*6236dae4SAndroid Build Coastguard Worker     "STARTTLS",
355*6236dae4SAndroid Build Coastguard Worker     "UPGRADETLS",
356*6236dae4SAndroid Build Coastguard Worker     "AUTH",
357*6236dae4SAndroid Build Coastguard Worker     "APOP",
358*6236dae4SAndroid Build Coastguard Worker     "USER",
359*6236dae4SAndroid Build Coastguard Worker     "PASS",
360*6236dae4SAndroid Build Coastguard Worker     "COMMAND",
361*6236dae4SAndroid Build Coastguard Worker     "QUIT",
362*6236dae4SAndroid Build Coastguard Worker     /* LAST */
363*6236dae4SAndroid Build Coastguard Worker   };
364*6236dae4SAndroid Build Coastguard Worker 
365*6236dae4SAndroid Build Coastguard Worker   if(pop3c->state != newstate)
366*6236dae4SAndroid Build Coastguard Worker     infof(data, "POP3 %p state change from %s to %s",
367*6236dae4SAndroid Build Coastguard Worker           (void *)pop3c, names[pop3c->state], names[newstate]);
368*6236dae4SAndroid Build Coastguard Worker #endif
369*6236dae4SAndroid Build Coastguard Worker 
370*6236dae4SAndroid Build Coastguard Worker   pop3c->state = newstate;
371*6236dae4SAndroid Build Coastguard Worker }
372*6236dae4SAndroid Build Coastguard Worker 
373*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
374*6236dae4SAndroid Build Coastguard Worker  *
375*6236dae4SAndroid Build Coastguard Worker  * pop3_perform_capa()
376*6236dae4SAndroid Build Coastguard Worker  *
377*6236dae4SAndroid Build Coastguard Worker  * Sends the CAPA command in order to obtain a list of server side supported
378*6236dae4SAndroid Build Coastguard Worker  * capabilities.
379*6236dae4SAndroid Build Coastguard Worker  */
pop3_perform_capa(struct Curl_easy * data,struct connectdata * conn)380*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform_capa(struct Curl_easy *data,
381*6236dae4SAndroid Build Coastguard Worker                                   struct connectdata *conn)
382*6236dae4SAndroid Build Coastguard Worker {
383*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
384*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
385*6236dae4SAndroid Build Coastguard Worker 
386*6236dae4SAndroid Build Coastguard Worker   pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
387*6236dae4SAndroid Build Coastguard Worker   pop3c->sasl.authused = SASL_AUTH_NONE;  /* Clear the auth. mechanism used */
388*6236dae4SAndroid Build Coastguard Worker   pop3c->tls_supported = FALSE;           /* Clear the TLS capability */
389*6236dae4SAndroid Build Coastguard Worker 
390*6236dae4SAndroid Build Coastguard Worker   /* Send the CAPA command */
391*6236dae4SAndroid Build Coastguard Worker   result = Curl_pp_sendf(data, &pop3c->pp, "%s", "CAPA");
392*6236dae4SAndroid Build Coastguard Worker 
393*6236dae4SAndroid Build Coastguard Worker   if(!result)
394*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_CAPA);
395*6236dae4SAndroid Build Coastguard Worker 
396*6236dae4SAndroid Build Coastguard Worker   return result;
397*6236dae4SAndroid Build Coastguard Worker }
398*6236dae4SAndroid Build Coastguard Worker 
399*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
400*6236dae4SAndroid Build Coastguard Worker  *
401*6236dae4SAndroid Build Coastguard Worker  * pop3_perform_starttls()
402*6236dae4SAndroid Build Coastguard Worker  *
403*6236dae4SAndroid Build Coastguard Worker  * Sends the STLS command to start the upgrade to TLS.
404*6236dae4SAndroid Build Coastguard Worker  */
pop3_perform_starttls(struct Curl_easy * data,struct connectdata * conn)405*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform_starttls(struct Curl_easy *data,
406*6236dae4SAndroid Build Coastguard Worker                                       struct connectdata *conn)
407*6236dae4SAndroid Build Coastguard Worker {
408*6236dae4SAndroid Build Coastguard Worker   /* Send the STLS command */
409*6236dae4SAndroid Build Coastguard Worker   CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "STLS");
410*6236dae4SAndroid Build Coastguard Worker 
411*6236dae4SAndroid Build Coastguard Worker   if(!result)
412*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_STARTTLS);
413*6236dae4SAndroid Build Coastguard Worker 
414*6236dae4SAndroid Build Coastguard Worker   return result;
415*6236dae4SAndroid Build Coastguard Worker }
416*6236dae4SAndroid Build Coastguard Worker 
417*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
418*6236dae4SAndroid Build Coastguard Worker  *
419*6236dae4SAndroid Build Coastguard Worker  * pop3_perform_upgrade_tls()
420*6236dae4SAndroid Build Coastguard Worker  *
421*6236dae4SAndroid Build Coastguard Worker  * Performs the upgrade to TLS.
422*6236dae4SAndroid Build Coastguard Worker  */
pop3_perform_upgrade_tls(struct Curl_easy * data,struct connectdata * conn)423*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
424*6236dae4SAndroid Build Coastguard Worker                                          struct connectdata *conn)
425*6236dae4SAndroid Build Coastguard Worker {
426*6236dae4SAndroid Build Coastguard Worker   /* Start the SSL connection */
427*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
428*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
429*6236dae4SAndroid Build Coastguard Worker   bool ssldone = FALSE;
430*6236dae4SAndroid Build Coastguard Worker 
431*6236dae4SAndroid Build Coastguard Worker   if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
432*6236dae4SAndroid Build Coastguard Worker     result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
433*6236dae4SAndroid Build Coastguard Worker     if(result)
434*6236dae4SAndroid Build Coastguard Worker       goto out;
435*6236dae4SAndroid Build Coastguard Worker   }
436*6236dae4SAndroid Build Coastguard Worker 
437*6236dae4SAndroid Build Coastguard Worker   result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
438*6236dae4SAndroid Build Coastguard Worker 
439*6236dae4SAndroid Build Coastguard Worker   if(!result) {
440*6236dae4SAndroid Build Coastguard Worker     pop3c->ssldone = ssldone;
441*6236dae4SAndroid Build Coastguard Worker     if(pop3c->state != POP3_UPGRADETLS)
442*6236dae4SAndroid Build Coastguard Worker       pop3_state(data, POP3_UPGRADETLS);
443*6236dae4SAndroid Build Coastguard Worker 
444*6236dae4SAndroid Build Coastguard Worker     if(pop3c->ssldone) {
445*6236dae4SAndroid Build Coastguard Worker       pop3_to_pop3s(conn);
446*6236dae4SAndroid Build Coastguard Worker       result = pop3_perform_capa(data, conn);
447*6236dae4SAndroid Build Coastguard Worker     }
448*6236dae4SAndroid Build Coastguard Worker   }
449*6236dae4SAndroid Build Coastguard Worker out:
450*6236dae4SAndroid Build Coastguard Worker   return result;
451*6236dae4SAndroid Build Coastguard Worker }
452*6236dae4SAndroid Build Coastguard Worker 
453*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
454*6236dae4SAndroid Build Coastguard Worker  *
455*6236dae4SAndroid Build Coastguard Worker  * pop3_perform_user()
456*6236dae4SAndroid Build Coastguard Worker  *
457*6236dae4SAndroid Build Coastguard Worker  * Sends a clear text USER command to authenticate with.
458*6236dae4SAndroid Build Coastguard Worker  */
pop3_perform_user(struct Curl_easy * data,struct connectdata * conn)459*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform_user(struct Curl_easy *data,
460*6236dae4SAndroid Build Coastguard Worker                                   struct connectdata *conn)
461*6236dae4SAndroid Build Coastguard Worker {
462*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
463*6236dae4SAndroid Build Coastguard Worker 
464*6236dae4SAndroid Build Coastguard Worker   /* Check we have a username and password to authenticate with and end the
465*6236dae4SAndroid Build Coastguard Worker      connect phase if we do not */
466*6236dae4SAndroid Build Coastguard Worker   if(!data->state.aptr.user) {
467*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_STOP);
468*6236dae4SAndroid Build Coastguard Worker 
469*6236dae4SAndroid Build Coastguard Worker     return result;
470*6236dae4SAndroid Build Coastguard Worker   }
471*6236dae4SAndroid Build Coastguard Worker 
472*6236dae4SAndroid Build Coastguard Worker   /* Send the USER command */
473*6236dae4SAndroid Build Coastguard Worker   result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "USER %s",
474*6236dae4SAndroid Build Coastguard Worker                          conn->user ? conn->user : "");
475*6236dae4SAndroid Build Coastguard Worker   if(!result)
476*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_USER);
477*6236dae4SAndroid Build Coastguard Worker 
478*6236dae4SAndroid Build Coastguard Worker   return result;
479*6236dae4SAndroid Build Coastguard Worker }
480*6236dae4SAndroid Build Coastguard Worker 
481*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_DIGEST_AUTH
482*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
483*6236dae4SAndroid Build Coastguard Worker  *
484*6236dae4SAndroid Build Coastguard Worker  * pop3_perform_apop()
485*6236dae4SAndroid Build Coastguard Worker  *
486*6236dae4SAndroid Build Coastguard Worker  * Sends an APOP command to authenticate with.
487*6236dae4SAndroid Build Coastguard Worker  */
pop3_perform_apop(struct Curl_easy * data,struct connectdata * conn)488*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform_apop(struct Curl_easy *data,
489*6236dae4SAndroid Build Coastguard Worker                                   struct connectdata *conn)
490*6236dae4SAndroid Build Coastguard Worker {
491*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
492*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
493*6236dae4SAndroid Build Coastguard Worker   size_t i;
494*6236dae4SAndroid Build Coastguard Worker   struct MD5_context *ctxt;
495*6236dae4SAndroid Build Coastguard Worker   unsigned char digest[MD5_DIGEST_LEN];
496*6236dae4SAndroid Build Coastguard Worker   char secret[2 * MD5_DIGEST_LEN + 1];
497*6236dae4SAndroid Build Coastguard Worker 
498*6236dae4SAndroid Build Coastguard Worker   /* Check we have a username and password to authenticate with and end the
499*6236dae4SAndroid Build Coastguard Worker      connect phase if we do not */
500*6236dae4SAndroid Build Coastguard Worker   if(!data->state.aptr.user) {
501*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_STOP);
502*6236dae4SAndroid Build Coastguard Worker 
503*6236dae4SAndroid Build Coastguard Worker     return result;
504*6236dae4SAndroid Build Coastguard Worker   }
505*6236dae4SAndroid Build Coastguard Worker 
506*6236dae4SAndroid Build Coastguard Worker   /* Create the digest */
507*6236dae4SAndroid Build Coastguard Worker   ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
508*6236dae4SAndroid Build Coastguard Worker   if(!ctxt)
509*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
510*6236dae4SAndroid Build Coastguard Worker 
511*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
512*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(pop3c->apoptimestamp)));
513*6236dae4SAndroid Build Coastguard Worker 
514*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
515*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(conn->passwd)));
516*6236dae4SAndroid Build Coastguard Worker 
517*6236dae4SAndroid Build Coastguard Worker   /* Finalise the digest */
518*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_final(ctxt, digest);
519*6236dae4SAndroid Build Coastguard Worker 
520*6236dae4SAndroid Build Coastguard Worker   /* Convert the calculated 16 octet digest into a 32 byte hex string */
521*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < MD5_DIGEST_LEN; i++)
522*6236dae4SAndroid Build Coastguard Worker     msnprintf(&secret[2 * i], 3, "%02x", digest[i]);
523*6236dae4SAndroid Build Coastguard Worker 
524*6236dae4SAndroid Build Coastguard Worker   result = Curl_pp_sendf(data, &pop3c->pp, "APOP %s %s", conn->user, secret);
525*6236dae4SAndroid Build Coastguard Worker 
526*6236dae4SAndroid Build Coastguard Worker   if(!result)
527*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_APOP);
528*6236dae4SAndroid Build Coastguard Worker 
529*6236dae4SAndroid Build Coastguard Worker   return result;
530*6236dae4SAndroid Build Coastguard Worker }
531*6236dae4SAndroid Build Coastguard Worker #endif
532*6236dae4SAndroid Build Coastguard Worker 
533*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
534*6236dae4SAndroid Build Coastguard Worker  *
535*6236dae4SAndroid Build Coastguard Worker  * pop3_perform_auth()
536*6236dae4SAndroid Build Coastguard Worker  *
537*6236dae4SAndroid Build Coastguard Worker  * Sends an AUTH command allowing the client to login with the given SASL
538*6236dae4SAndroid Build Coastguard Worker  * authentication mechanism.
539*6236dae4SAndroid Build Coastguard Worker  */
pop3_perform_auth(struct Curl_easy * data,const char * mech,const struct bufref * initresp)540*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform_auth(struct Curl_easy *data,
541*6236dae4SAndroid Build Coastguard Worker                                   const char *mech,
542*6236dae4SAndroid Build Coastguard Worker                                   const struct bufref *initresp)
543*6236dae4SAndroid Build Coastguard Worker {
544*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
545*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &data->conn->proto.pop3c;
546*6236dae4SAndroid Build Coastguard Worker   const char *ir = (const char *) Curl_bufref_ptr(initresp);
547*6236dae4SAndroid Build Coastguard Worker 
548*6236dae4SAndroid Build Coastguard Worker   if(ir) {                                  /* AUTH <mech> ...<crlf> */
549*6236dae4SAndroid Build Coastguard Worker     /* Send the AUTH command with the initial response */
550*6236dae4SAndroid Build Coastguard Worker     result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, ir);
551*6236dae4SAndroid Build Coastguard Worker   }
552*6236dae4SAndroid Build Coastguard Worker   else {
553*6236dae4SAndroid Build Coastguard Worker     /* Send the AUTH command */
554*6236dae4SAndroid Build Coastguard Worker     result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s", mech);
555*6236dae4SAndroid Build Coastguard Worker   }
556*6236dae4SAndroid Build Coastguard Worker 
557*6236dae4SAndroid Build Coastguard Worker   return result;
558*6236dae4SAndroid Build Coastguard Worker }
559*6236dae4SAndroid Build Coastguard Worker 
560*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
561*6236dae4SAndroid Build Coastguard Worker  *
562*6236dae4SAndroid Build Coastguard Worker  * pop3_continue_auth()
563*6236dae4SAndroid Build Coastguard Worker  *
564*6236dae4SAndroid Build Coastguard Worker  * Sends SASL continuation data.
565*6236dae4SAndroid Build Coastguard Worker  */
pop3_continue_auth(struct Curl_easy * data,const char * mech,const struct bufref * resp)566*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_continue_auth(struct Curl_easy *data,
567*6236dae4SAndroid Build Coastguard Worker                                    const char *mech,
568*6236dae4SAndroid Build Coastguard Worker                                    const struct bufref *resp)
569*6236dae4SAndroid Build Coastguard Worker {
570*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &data->conn->proto.pop3c;
571*6236dae4SAndroid Build Coastguard Worker 
572*6236dae4SAndroid Build Coastguard Worker   (void)mech;
573*6236dae4SAndroid Build Coastguard Worker 
574*6236dae4SAndroid Build Coastguard Worker   return Curl_pp_sendf(data, &pop3c->pp,
575*6236dae4SAndroid Build Coastguard Worker                        "%s", (const char *) Curl_bufref_ptr(resp));
576*6236dae4SAndroid Build Coastguard Worker }
577*6236dae4SAndroid Build Coastguard Worker 
578*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
579*6236dae4SAndroid Build Coastguard Worker  *
580*6236dae4SAndroid Build Coastguard Worker  * pop3_cancel_auth()
581*6236dae4SAndroid Build Coastguard Worker  *
582*6236dae4SAndroid Build Coastguard Worker  * Sends SASL cancellation.
583*6236dae4SAndroid Build Coastguard Worker  */
pop3_cancel_auth(struct Curl_easy * data,const char * mech)584*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech)
585*6236dae4SAndroid Build Coastguard Worker {
586*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &data->conn->proto.pop3c;
587*6236dae4SAndroid Build Coastguard Worker 
588*6236dae4SAndroid Build Coastguard Worker   (void)mech;
589*6236dae4SAndroid Build Coastguard Worker 
590*6236dae4SAndroid Build Coastguard Worker   return Curl_pp_sendf(data, &pop3c->pp, "*");
591*6236dae4SAndroid Build Coastguard Worker }
592*6236dae4SAndroid Build Coastguard Worker 
593*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
594*6236dae4SAndroid Build Coastguard Worker  *
595*6236dae4SAndroid Build Coastguard Worker  * pop3_perform_authentication()
596*6236dae4SAndroid Build Coastguard Worker  *
597*6236dae4SAndroid Build Coastguard Worker  * Initiates the authentication sequence, with the appropriate SASL
598*6236dae4SAndroid Build Coastguard Worker  * authentication mechanism, falling back to APOP and clear text should a
599*6236dae4SAndroid Build Coastguard Worker  * common mechanism not be available between the client and server.
600*6236dae4SAndroid Build Coastguard Worker  */
pop3_perform_authentication(struct Curl_easy * data,struct connectdata * conn)601*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform_authentication(struct Curl_easy *data,
602*6236dae4SAndroid Build Coastguard Worker                                             struct connectdata *conn)
603*6236dae4SAndroid Build Coastguard Worker {
604*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
605*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
606*6236dae4SAndroid Build Coastguard Worker   saslprogress progress = SASL_IDLE;
607*6236dae4SAndroid Build Coastguard Worker 
608*6236dae4SAndroid Build Coastguard Worker   /* Check we have enough data to authenticate with and end the
609*6236dae4SAndroid Build Coastguard Worker      connect phase if we do not */
610*6236dae4SAndroid Build Coastguard Worker   if(!Curl_sasl_can_authenticate(&pop3c->sasl, data)) {
611*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_STOP);
612*6236dae4SAndroid Build Coastguard Worker     return result;
613*6236dae4SAndroid Build Coastguard Worker   }
614*6236dae4SAndroid Build Coastguard Worker 
615*6236dae4SAndroid Build Coastguard Worker   if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
616*6236dae4SAndroid Build Coastguard Worker     /* Calculate the SASL login details */
617*6236dae4SAndroid Build Coastguard Worker     result = Curl_sasl_start(&pop3c->sasl, data, FALSE, &progress);
618*6236dae4SAndroid Build Coastguard Worker 
619*6236dae4SAndroid Build Coastguard Worker     if(!result)
620*6236dae4SAndroid Build Coastguard Worker       if(progress == SASL_INPROGRESS)
621*6236dae4SAndroid Build Coastguard Worker         pop3_state(data, POP3_AUTH);
622*6236dae4SAndroid Build Coastguard Worker   }
623*6236dae4SAndroid Build Coastguard Worker 
624*6236dae4SAndroid Build Coastguard Worker   if(!result && progress == SASL_IDLE) {
625*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_DIGEST_AUTH
626*6236dae4SAndroid Build Coastguard Worker     if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
627*6236dae4SAndroid Build Coastguard Worker       /* Perform APOP authentication */
628*6236dae4SAndroid Build Coastguard Worker       result = pop3_perform_apop(data, conn);
629*6236dae4SAndroid Build Coastguard Worker     else
630*6236dae4SAndroid Build Coastguard Worker #endif
631*6236dae4SAndroid Build Coastguard Worker     if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
632*6236dae4SAndroid Build Coastguard Worker       /* Perform clear text authentication */
633*6236dae4SAndroid Build Coastguard Worker       result = pop3_perform_user(data, conn);
634*6236dae4SAndroid Build Coastguard Worker     else {
635*6236dae4SAndroid Build Coastguard Worker       /* Other mechanisms not supported */
636*6236dae4SAndroid Build Coastguard Worker       infof(data, "No known authentication mechanisms supported");
637*6236dae4SAndroid Build Coastguard Worker       result = CURLE_LOGIN_DENIED;
638*6236dae4SAndroid Build Coastguard Worker     }
639*6236dae4SAndroid Build Coastguard Worker   }
640*6236dae4SAndroid Build Coastguard Worker 
641*6236dae4SAndroid Build Coastguard Worker   return result;
642*6236dae4SAndroid Build Coastguard Worker }
643*6236dae4SAndroid Build Coastguard Worker 
644*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
645*6236dae4SAndroid Build Coastguard Worker  *
646*6236dae4SAndroid Build Coastguard Worker  * pop3_perform_command()
647*6236dae4SAndroid Build Coastguard Worker  *
648*6236dae4SAndroid Build Coastguard Worker  * Sends a POP3 based command.
649*6236dae4SAndroid Build Coastguard Worker  */
pop3_perform_command(struct Curl_easy * data)650*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform_command(struct Curl_easy *data)
651*6236dae4SAndroid Build Coastguard Worker {
652*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
653*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
654*6236dae4SAndroid Build Coastguard Worker   struct POP3 *pop3 = data->req.p.pop3;
655*6236dae4SAndroid Build Coastguard Worker   const char *command = NULL;
656*6236dae4SAndroid Build Coastguard Worker 
657*6236dae4SAndroid Build Coastguard Worker   /* Calculate the default command */
658*6236dae4SAndroid Build Coastguard Worker   if(pop3->id[0] == '\0' || data->set.list_only) {
659*6236dae4SAndroid Build Coastguard Worker     command = "LIST";
660*6236dae4SAndroid Build Coastguard Worker 
661*6236dae4SAndroid Build Coastguard Worker     if(pop3->id[0] != '\0')
662*6236dae4SAndroid Build Coastguard Worker       /* Message specific LIST so skip the BODY transfer */
663*6236dae4SAndroid Build Coastguard Worker       pop3->transfer = PPTRANSFER_INFO;
664*6236dae4SAndroid Build Coastguard Worker   }
665*6236dae4SAndroid Build Coastguard Worker   else
666*6236dae4SAndroid Build Coastguard Worker     command = "RETR";
667*6236dae4SAndroid Build Coastguard Worker 
668*6236dae4SAndroid Build Coastguard Worker   if(pop3->custom && pop3->custom[0] != '\0')
669*6236dae4SAndroid Build Coastguard Worker     command = pop3->custom;
670*6236dae4SAndroid Build Coastguard Worker 
671*6236dae4SAndroid Build Coastguard Worker   /* Send the command */
672*6236dae4SAndroid Build Coastguard Worker   if(pop3->id[0] != '\0')
673*6236dae4SAndroid Build Coastguard Worker     result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s %s",
674*6236dae4SAndroid Build Coastguard Worker                            command, pop3->id);
675*6236dae4SAndroid Build Coastguard Worker   else
676*6236dae4SAndroid Build Coastguard Worker     result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", command);
677*6236dae4SAndroid Build Coastguard Worker 
678*6236dae4SAndroid Build Coastguard Worker   if(!result) {
679*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_COMMAND);
680*6236dae4SAndroid Build Coastguard Worker     data->req.no_body = !pop3_is_multiline(command);
681*6236dae4SAndroid Build Coastguard Worker   }
682*6236dae4SAndroid Build Coastguard Worker 
683*6236dae4SAndroid Build Coastguard Worker   return result;
684*6236dae4SAndroid Build Coastguard Worker }
685*6236dae4SAndroid Build Coastguard Worker 
686*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
687*6236dae4SAndroid Build Coastguard Worker  *
688*6236dae4SAndroid Build Coastguard Worker  * pop3_perform_quit()
689*6236dae4SAndroid Build Coastguard Worker  *
690*6236dae4SAndroid Build Coastguard Worker  * Performs the quit action prior to sclose() be called.
691*6236dae4SAndroid Build Coastguard Worker  */
pop3_perform_quit(struct Curl_easy * data,struct connectdata * conn)692*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform_quit(struct Curl_easy *data,
693*6236dae4SAndroid Build Coastguard Worker                                   struct connectdata *conn)
694*6236dae4SAndroid Build Coastguard Worker {
695*6236dae4SAndroid Build Coastguard Worker   /* Send the QUIT command */
696*6236dae4SAndroid Build Coastguard Worker   CURLcode result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", "QUIT");
697*6236dae4SAndroid Build Coastguard Worker 
698*6236dae4SAndroid Build Coastguard Worker   if(!result)
699*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_QUIT);
700*6236dae4SAndroid Build Coastguard Worker 
701*6236dae4SAndroid Build Coastguard Worker   return result;
702*6236dae4SAndroid Build Coastguard Worker }
703*6236dae4SAndroid Build Coastguard Worker 
704*6236dae4SAndroid Build Coastguard Worker /* For the initial server greeting */
pop3_state_servergreet_resp(struct Curl_easy * data,int pop3code,pop3state instate)705*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data,
706*6236dae4SAndroid Build Coastguard Worker                                             int pop3code,
707*6236dae4SAndroid Build Coastguard Worker                                             pop3state instate)
708*6236dae4SAndroid Build Coastguard Worker {
709*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
710*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
711*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
712*6236dae4SAndroid Build Coastguard Worker   const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
713*6236dae4SAndroid Build Coastguard Worker   size_t len = data->conn->proto.pop3c.pp.nfinal;
714*6236dae4SAndroid Build Coastguard Worker 
715*6236dae4SAndroid Build Coastguard Worker   (void)instate; /* no use for this yet */
716*6236dae4SAndroid Build Coastguard Worker 
717*6236dae4SAndroid Build Coastguard Worker   if(pop3code != '+') {
718*6236dae4SAndroid Build Coastguard Worker     failf(data, "Got unexpected pop3-server response");
719*6236dae4SAndroid Build Coastguard Worker     result = CURLE_WEIRD_SERVER_REPLY;
720*6236dae4SAndroid Build Coastguard Worker   }
721*6236dae4SAndroid Build Coastguard Worker   else if(len > 3) {
722*6236dae4SAndroid Build Coastguard Worker     /* Does the server support APOP authentication? */
723*6236dae4SAndroid Build Coastguard Worker     char *lt;
724*6236dae4SAndroid Build Coastguard Worker     char *gt = NULL;
725*6236dae4SAndroid Build Coastguard Worker 
726*6236dae4SAndroid Build Coastguard Worker     /* Look for the APOP timestamp */
727*6236dae4SAndroid Build Coastguard Worker     lt = memchr(line, '<', len);
728*6236dae4SAndroid Build Coastguard Worker     if(lt)
729*6236dae4SAndroid Build Coastguard Worker       /* search the remainder for '>' */
730*6236dae4SAndroid Build Coastguard Worker       gt = memchr(lt, '>', len - (lt - line));
731*6236dae4SAndroid Build Coastguard Worker     if(gt) {
732*6236dae4SAndroid Build Coastguard Worker       /* the length of the timestamp, including the brackets */
733*6236dae4SAndroid Build Coastguard Worker       size_t timestamplen = gt - lt + 1;
734*6236dae4SAndroid Build Coastguard Worker       char *at = memchr(lt, '@', timestamplen);
735*6236dae4SAndroid Build Coastguard Worker       /* If the timestamp does not contain '@' it is not (as required by
736*6236dae4SAndroid Build Coastguard Worker          RFC-1939) conformant to the RFC-822 message id syntax, and we
737*6236dae4SAndroid Build Coastguard Worker          therefore do not use APOP authentication. */
738*6236dae4SAndroid Build Coastguard Worker       if(at) {
739*6236dae4SAndroid Build Coastguard Worker         /* dupe the timestamp */
740*6236dae4SAndroid Build Coastguard Worker         pop3c->apoptimestamp = Curl_memdup0(lt, timestamplen);
741*6236dae4SAndroid Build Coastguard Worker         if(!pop3c->apoptimestamp)
742*6236dae4SAndroid Build Coastguard Worker           return CURLE_OUT_OF_MEMORY;
743*6236dae4SAndroid Build Coastguard Worker         /* Store the APOP capability */
744*6236dae4SAndroid Build Coastguard Worker         pop3c->authtypes |= POP3_TYPE_APOP;
745*6236dae4SAndroid Build Coastguard Worker       }
746*6236dae4SAndroid Build Coastguard Worker     }
747*6236dae4SAndroid Build Coastguard Worker 
748*6236dae4SAndroid Build Coastguard Worker     if(!result)
749*6236dae4SAndroid Build Coastguard Worker       result = pop3_perform_capa(data, conn);
750*6236dae4SAndroid Build Coastguard Worker   }
751*6236dae4SAndroid Build Coastguard Worker 
752*6236dae4SAndroid Build Coastguard Worker   return result;
753*6236dae4SAndroid Build Coastguard Worker }
754*6236dae4SAndroid Build Coastguard Worker 
755*6236dae4SAndroid Build Coastguard Worker /* For CAPA responses */
pop3_state_capa_resp(struct Curl_easy * data,int pop3code,pop3state instate)756*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code,
757*6236dae4SAndroid Build Coastguard Worker                                      pop3state instate)
758*6236dae4SAndroid Build Coastguard Worker {
759*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
760*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
761*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
762*6236dae4SAndroid Build Coastguard Worker   const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
763*6236dae4SAndroid Build Coastguard Worker   size_t len = data->conn->proto.pop3c.pp.nfinal;
764*6236dae4SAndroid Build Coastguard Worker 
765*6236dae4SAndroid Build Coastguard Worker   (void)instate; /* no use for this yet */
766*6236dae4SAndroid Build Coastguard Worker 
767*6236dae4SAndroid Build Coastguard Worker   /* Do we have a untagged continuation response? */
768*6236dae4SAndroid Build Coastguard Worker   if(pop3code == '*') {
769*6236dae4SAndroid Build Coastguard Worker     /* Does the server support the STLS capability? */
770*6236dae4SAndroid Build Coastguard Worker     if(len >= 4 && !memcmp(line, "STLS", 4))
771*6236dae4SAndroid Build Coastguard Worker       pop3c->tls_supported = TRUE;
772*6236dae4SAndroid Build Coastguard Worker 
773*6236dae4SAndroid Build Coastguard Worker     /* Does the server support clear text authentication? */
774*6236dae4SAndroid Build Coastguard Worker     else if(len >= 4 && !memcmp(line, "USER", 4))
775*6236dae4SAndroid Build Coastguard Worker       pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
776*6236dae4SAndroid Build Coastguard Worker 
777*6236dae4SAndroid Build Coastguard Worker     /* Does the server support SASL based authentication? */
778*6236dae4SAndroid Build Coastguard Worker     else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
779*6236dae4SAndroid Build Coastguard Worker       pop3c->authtypes |= POP3_TYPE_SASL;
780*6236dae4SAndroid Build Coastguard Worker 
781*6236dae4SAndroid Build Coastguard Worker       /* Advance past the SASL keyword */
782*6236dae4SAndroid Build Coastguard Worker       line += 5;
783*6236dae4SAndroid Build Coastguard Worker       len -= 5;
784*6236dae4SAndroid Build Coastguard Worker 
785*6236dae4SAndroid Build Coastguard Worker       /* Loop through the data line */
786*6236dae4SAndroid Build Coastguard Worker       for(;;) {
787*6236dae4SAndroid Build Coastguard Worker         size_t llen;
788*6236dae4SAndroid Build Coastguard Worker         size_t wordlen;
789*6236dae4SAndroid Build Coastguard Worker         unsigned short mechbit;
790*6236dae4SAndroid Build Coastguard Worker 
791*6236dae4SAndroid Build Coastguard Worker         while(len &&
792*6236dae4SAndroid Build Coastguard Worker               (*line == ' ' || *line == '\t' ||
793*6236dae4SAndroid Build Coastguard Worker                *line == '\r' || *line == '\n')) {
794*6236dae4SAndroid Build Coastguard Worker 
795*6236dae4SAndroid Build Coastguard Worker           line++;
796*6236dae4SAndroid Build Coastguard Worker           len--;
797*6236dae4SAndroid Build Coastguard Worker         }
798*6236dae4SAndroid Build Coastguard Worker 
799*6236dae4SAndroid Build Coastguard Worker         if(!len)
800*6236dae4SAndroid Build Coastguard Worker           break;
801*6236dae4SAndroid Build Coastguard Worker 
802*6236dae4SAndroid Build Coastguard Worker         /* Extract the word */
803*6236dae4SAndroid Build Coastguard Worker         for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
804*6236dae4SAndroid Build Coastguard Worker               line[wordlen] != '\t' && line[wordlen] != '\r' &&
805*6236dae4SAndroid Build Coastguard Worker               line[wordlen] != '\n';)
806*6236dae4SAndroid Build Coastguard Worker           wordlen++;
807*6236dae4SAndroid Build Coastguard Worker 
808*6236dae4SAndroid Build Coastguard Worker         /* Test the word for a matching authentication mechanism */
809*6236dae4SAndroid Build Coastguard Worker         mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
810*6236dae4SAndroid Build Coastguard Worker         if(mechbit && llen == wordlen)
811*6236dae4SAndroid Build Coastguard Worker           pop3c->sasl.authmechs |= mechbit;
812*6236dae4SAndroid Build Coastguard Worker 
813*6236dae4SAndroid Build Coastguard Worker         line += wordlen;
814*6236dae4SAndroid Build Coastguard Worker         len -= wordlen;
815*6236dae4SAndroid Build Coastguard Worker       }
816*6236dae4SAndroid Build Coastguard Worker     }
817*6236dae4SAndroid Build Coastguard Worker   }
818*6236dae4SAndroid Build Coastguard Worker   else {
819*6236dae4SAndroid Build Coastguard Worker     /* Clear text is supported when CAPA is not recognised */
820*6236dae4SAndroid Build Coastguard Worker     if(pop3code != '+')
821*6236dae4SAndroid Build Coastguard Worker       pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
822*6236dae4SAndroid Build Coastguard Worker 
823*6236dae4SAndroid Build Coastguard Worker     if(!data->set.use_ssl || Curl_conn_is_ssl(conn, FIRSTSOCKET))
824*6236dae4SAndroid Build Coastguard Worker       result = pop3_perform_authentication(data, conn);
825*6236dae4SAndroid Build Coastguard Worker     else if(pop3code == '+' && pop3c->tls_supported)
826*6236dae4SAndroid Build Coastguard Worker       /* Switch to TLS connection now */
827*6236dae4SAndroid Build Coastguard Worker       result = pop3_perform_starttls(data, conn);
828*6236dae4SAndroid Build Coastguard Worker     else if(data->set.use_ssl <= CURLUSESSL_TRY)
829*6236dae4SAndroid Build Coastguard Worker       /* Fallback and carry on with authentication */
830*6236dae4SAndroid Build Coastguard Worker       result = pop3_perform_authentication(data, conn);
831*6236dae4SAndroid Build Coastguard Worker     else {
832*6236dae4SAndroid Build Coastguard Worker       failf(data, "STLS not supported.");
833*6236dae4SAndroid Build Coastguard Worker       result = CURLE_USE_SSL_FAILED;
834*6236dae4SAndroid Build Coastguard Worker     }
835*6236dae4SAndroid Build Coastguard Worker   }
836*6236dae4SAndroid Build Coastguard Worker 
837*6236dae4SAndroid Build Coastguard Worker   return result;
838*6236dae4SAndroid Build Coastguard Worker }
839*6236dae4SAndroid Build Coastguard Worker 
840*6236dae4SAndroid Build Coastguard Worker /* For STARTTLS responses */
pop3_state_starttls_resp(struct Curl_easy * data,struct connectdata * conn,int pop3code,pop3state instate)841*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_state_starttls_resp(struct Curl_easy *data,
842*6236dae4SAndroid Build Coastguard Worker                                          struct connectdata *conn,
843*6236dae4SAndroid Build Coastguard Worker                                          int pop3code,
844*6236dae4SAndroid Build Coastguard Worker                                          pop3state instate)
845*6236dae4SAndroid Build Coastguard Worker {
846*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
847*6236dae4SAndroid Build Coastguard Worker   (void)instate; /* no use for this yet */
848*6236dae4SAndroid Build Coastguard Worker 
849*6236dae4SAndroid Build Coastguard Worker   /* Pipelining in response is forbidden. */
850*6236dae4SAndroid Build Coastguard Worker   if(data->conn->proto.pop3c.pp.overflow)
851*6236dae4SAndroid Build Coastguard Worker     return CURLE_WEIRD_SERVER_REPLY;
852*6236dae4SAndroid Build Coastguard Worker 
853*6236dae4SAndroid Build Coastguard Worker   if(pop3code != '+') {
854*6236dae4SAndroid Build Coastguard Worker     if(data->set.use_ssl != CURLUSESSL_TRY) {
855*6236dae4SAndroid Build Coastguard Worker       failf(data, "STARTTLS denied");
856*6236dae4SAndroid Build Coastguard Worker       result = CURLE_USE_SSL_FAILED;
857*6236dae4SAndroid Build Coastguard Worker     }
858*6236dae4SAndroid Build Coastguard Worker     else
859*6236dae4SAndroid Build Coastguard Worker       result = pop3_perform_authentication(data, conn);
860*6236dae4SAndroid Build Coastguard Worker   }
861*6236dae4SAndroid Build Coastguard Worker   else
862*6236dae4SAndroid Build Coastguard Worker     result = pop3_perform_upgrade_tls(data, conn);
863*6236dae4SAndroid Build Coastguard Worker 
864*6236dae4SAndroid Build Coastguard Worker   return result;
865*6236dae4SAndroid Build Coastguard Worker }
866*6236dae4SAndroid Build Coastguard Worker 
867*6236dae4SAndroid Build Coastguard Worker /* For SASL authentication responses */
pop3_state_auth_resp(struct Curl_easy * data,int pop3code,pop3state instate)868*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_state_auth_resp(struct Curl_easy *data,
869*6236dae4SAndroid Build Coastguard Worker                                      int pop3code,
870*6236dae4SAndroid Build Coastguard Worker                                      pop3state instate)
871*6236dae4SAndroid Build Coastguard Worker {
872*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
873*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
874*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
875*6236dae4SAndroid Build Coastguard Worker   saslprogress progress;
876*6236dae4SAndroid Build Coastguard Worker 
877*6236dae4SAndroid Build Coastguard Worker   (void)instate; /* no use for this yet */
878*6236dae4SAndroid Build Coastguard Worker 
879*6236dae4SAndroid Build Coastguard Worker   result = Curl_sasl_continue(&pop3c->sasl, data, pop3code, &progress);
880*6236dae4SAndroid Build Coastguard Worker   if(!result)
881*6236dae4SAndroid Build Coastguard Worker     switch(progress) {
882*6236dae4SAndroid Build Coastguard Worker     case SASL_DONE:
883*6236dae4SAndroid Build Coastguard Worker       pop3_state(data, POP3_STOP);  /* Authenticated */
884*6236dae4SAndroid Build Coastguard Worker       break;
885*6236dae4SAndroid Build Coastguard Worker     case SASL_IDLE:            /* No mechanism left after cancellation */
886*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_DIGEST_AUTH
887*6236dae4SAndroid Build Coastguard Worker       if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
888*6236dae4SAndroid Build Coastguard Worker         /* Perform APOP authentication */
889*6236dae4SAndroid Build Coastguard Worker         result = pop3_perform_apop(data, conn);
890*6236dae4SAndroid Build Coastguard Worker       else
891*6236dae4SAndroid Build Coastguard Worker #endif
892*6236dae4SAndroid Build Coastguard Worker       if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
893*6236dae4SAndroid Build Coastguard Worker         /* Perform clear text authentication */
894*6236dae4SAndroid Build Coastguard Worker         result = pop3_perform_user(data, conn);
895*6236dae4SAndroid Build Coastguard Worker       else {
896*6236dae4SAndroid Build Coastguard Worker         failf(data, "Authentication cancelled");
897*6236dae4SAndroid Build Coastguard Worker         result = CURLE_LOGIN_DENIED;
898*6236dae4SAndroid Build Coastguard Worker       }
899*6236dae4SAndroid Build Coastguard Worker       break;
900*6236dae4SAndroid Build Coastguard Worker     default:
901*6236dae4SAndroid Build Coastguard Worker       break;
902*6236dae4SAndroid Build Coastguard Worker     }
903*6236dae4SAndroid Build Coastguard Worker 
904*6236dae4SAndroid Build Coastguard Worker   return result;
905*6236dae4SAndroid Build Coastguard Worker }
906*6236dae4SAndroid Build Coastguard Worker 
907*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_DIGEST_AUTH
908*6236dae4SAndroid Build Coastguard Worker /* For APOP responses */
pop3_state_apop_resp(struct Curl_easy * data,int pop3code,pop3state instate)909*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_state_apop_resp(struct Curl_easy *data, int pop3code,
910*6236dae4SAndroid Build Coastguard Worker                                      pop3state instate)
911*6236dae4SAndroid Build Coastguard Worker {
912*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
913*6236dae4SAndroid Build Coastguard Worker   (void)instate; /* no use for this yet */
914*6236dae4SAndroid Build Coastguard Worker 
915*6236dae4SAndroid Build Coastguard Worker   if(pop3code != '+') {
916*6236dae4SAndroid Build Coastguard Worker     failf(data, "Authentication failed: %d", pop3code);
917*6236dae4SAndroid Build Coastguard Worker     result = CURLE_LOGIN_DENIED;
918*6236dae4SAndroid Build Coastguard Worker   }
919*6236dae4SAndroid Build Coastguard Worker   else
920*6236dae4SAndroid Build Coastguard Worker     /* End of connect phase */
921*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_STOP);
922*6236dae4SAndroid Build Coastguard Worker 
923*6236dae4SAndroid Build Coastguard Worker   return result;
924*6236dae4SAndroid Build Coastguard Worker }
925*6236dae4SAndroid Build Coastguard Worker #endif
926*6236dae4SAndroid Build Coastguard Worker 
927*6236dae4SAndroid Build Coastguard Worker /* For USER responses */
pop3_state_user_resp(struct Curl_easy * data,int pop3code,pop3state instate)928*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code,
929*6236dae4SAndroid Build Coastguard Worker                                      pop3state instate)
930*6236dae4SAndroid Build Coastguard Worker {
931*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
932*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
933*6236dae4SAndroid Build Coastguard Worker   (void)instate; /* no use for this yet */
934*6236dae4SAndroid Build Coastguard Worker 
935*6236dae4SAndroid Build Coastguard Worker   if(pop3code != '+') {
936*6236dae4SAndroid Build Coastguard Worker     failf(data, "Access denied. %c", pop3code);
937*6236dae4SAndroid Build Coastguard Worker     result = CURLE_LOGIN_DENIED;
938*6236dae4SAndroid Build Coastguard Worker   }
939*6236dae4SAndroid Build Coastguard Worker   else
940*6236dae4SAndroid Build Coastguard Worker     /* Send the PASS command */
941*6236dae4SAndroid Build Coastguard Worker     result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "PASS %s",
942*6236dae4SAndroid Build Coastguard Worker                            conn->passwd ? conn->passwd : "");
943*6236dae4SAndroid Build Coastguard Worker   if(!result)
944*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_PASS);
945*6236dae4SAndroid Build Coastguard Worker 
946*6236dae4SAndroid Build Coastguard Worker   return result;
947*6236dae4SAndroid Build Coastguard Worker }
948*6236dae4SAndroid Build Coastguard Worker 
949*6236dae4SAndroid Build Coastguard Worker /* For PASS responses */
pop3_state_pass_resp(struct Curl_easy * data,int pop3code,pop3state instate)950*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_state_pass_resp(struct Curl_easy *data, int pop3code,
951*6236dae4SAndroid Build Coastguard Worker                                      pop3state instate)
952*6236dae4SAndroid Build Coastguard Worker {
953*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
954*6236dae4SAndroid Build Coastguard Worker   (void)instate; /* no use for this yet */
955*6236dae4SAndroid Build Coastguard Worker 
956*6236dae4SAndroid Build Coastguard Worker   if(pop3code != '+') {
957*6236dae4SAndroid Build Coastguard Worker     failf(data, "Access denied. %c", pop3code);
958*6236dae4SAndroid Build Coastguard Worker     result = CURLE_LOGIN_DENIED;
959*6236dae4SAndroid Build Coastguard Worker   }
960*6236dae4SAndroid Build Coastguard Worker   else
961*6236dae4SAndroid Build Coastguard Worker     /* End of connect phase */
962*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_STOP);
963*6236dae4SAndroid Build Coastguard Worker 
964*6236dae4SAndroid Build Coastguard Worker   return result;
965*6236dae4SAndroid Build Coastguard Worker }
966*6236dae4SAndroid Build Coastguard Worker 
967*6236dae4SAndroid Build Coastguard Worker /* For command responses */
pop3_state_command_resp(struct Curl_easy * data,int pop3code,pop3state instate)968*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_state_command_resp(struct Curl_easy *data,
969*6236dae4SAndroid Build Coastguard Worker                                         int pop3code,
970*6236dae4SAndroid Build Coastguard Worker                                         pop3state instate)
971*6236dae4SAndroid Build Coastguard Worker {
972*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
973*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
974*6236dae4SAndroid Build Coastguard Worker   struct POP3 *pop3 = data->req.p.pop3;
975*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
976*6236dae4SAndroid Build Coastguard Worker   struct pingpong *pp = &pop3c->pp;
977*6236dae4SAndroid Build Coastguard Worker 
978*6236dae4SAndroid Build Coastguard Worker   (void)instate; /* no use for this yet */
979*6236dae4SAndroid Build Coastguard Worker 
980*6236dae4SAndroid Build Coastguard Worker   if(pop3code != '+') {
981*6236dae4SAndroid Build Coastguard Worker     pop3_state(data, POP3_STOP);
982*6236dae4SAndroid Build Coastguard Worker     return CURLE_WEIRD_SERVER_REPLY;
983*6236dae4SAndroid Build Coastguard Worker   }
984*6236dae4SAndroid Build Coastguard Worker 
985*6236dae4SAndroid Build Coastguard Worker   /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
986*6236dae4SAndroid Build Coastguard Worker      EOB string so count this is two matching bytes. This is necessary to make
987*6236dae4SAndroid Build Coastguard Worker      the code detect the EOB if the only data than comes now is %2e CR LF like
988*6236dae4SAndroid Build Coastguard Worker      when there is no body to return. */
989*6236dae4SAndroid Build Coastguard Worker   pop3c->eob = 2;
990*6236dae4SAndroid Build Coastguard Worker 
991*6236dae4SAndroid Build Coastguard Worker   /* But since this initial CR LF pair is not part of the actual body, we set
992*6236dae4SAndroid Build Coastguard Worker      the strip counter here so that these bytes will not be delivered. */
993*6236dae4SAndroid Build Coastguard Worker   pop3c->strip = 2;
994*6236dae4SAndroid Build Coastguard Worker 
995*6236dae4SAndroid Build Coastguard Worker   if(pop3->transfer == PPTRANSFER_BODY) {
996*6236dae4SAndroid Build Coastguard Worker     /* POP3 download */
997*6236dae4SAndroid Build Coastguard Worker     Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
998*6236dae4SAndroid Build Coastguard Worker 
999*6236dae4SAndroid Build Coastguard Worker     if(pp->overflow) {
1000*6236dae4SAndroid Build Coastguard Worker       /* The recv buffer contains data that is actually body content so send
1001*6236dae4SAndroid Build Coastguard Worker          it as such. Note that there may even be additional "headers" after
1002*6236dae4SAndroid Build Coastguard Worker          the body */
1003*6236dae4SAndroid Build Coastguard Worker 
1004*6236dae4SAndroid Build Coastguard Worker       /* keep only the overflow */
1005*6236dae4SAndroid Build Coastguard Worker       Curl_dyn_tail(&pp->recvbuf, pp->overflow);
1006*6236dae4SAndroid Build Coastguard Worker       pp->nfinal = 0; /* done */
1007*6236dae4SAndroid Build Coastguard Worker 
1008*6236dae4SAndroid Build Coastguard Worker       if(!data->req.no_body) {
1009*6236dae4SAndroid Build Coastguard Worker         result = pop3_write(data, Curl_dyn_ptr(&pp->recvbuf),
1010*6236dae4SAndroid Build Coastguard Worker                             Curl_dyn_len(&pp->recvbuf), FALSE);
1011*6236dae4SAndroid Build Coastguard Worker         if(result)
1012*6236dae4SAndroid Build Coastguard Worker           return result;
1013*6236dae4SAndroid Build Coastguard Worker       }
1014*6236dae4SAndroid Build Coastguard Worker 
1015*6236dae4SAndroid Build Coastguard Worker       /* reset the buffer */
1016*6236dae4SAndroid Build Coastguard Worker       Curl_dyn_reset(&pp->recvbuf);
1017*6236dae4SAndroid Build Coastguard Worker       pp->overflow = 0;
1018*6236dae4SAndroid Build Coastguard Worker     }
1019*6236dae4SAndroid Build Coastguard Worker   }
1020*6236dae4SAndroid Build Coastguard Worker   else
1021*6236dae4SAndroid Build Coastguard Worker     pp->overflow = 0;
1022*6236dae4SAndroid Build Coastguard Worker 
1023*6236dae4SAndroid Build Coastguard Worker   /* End of DO phase */
1024*6236dae4SAndroid Build Coastguard Worker   pop3_state(data, POP3_STOP);
1025*6236dae4SAndroid Build Coastguard Worker 
1026*6236dae4SAndroid Build Coastguard Worker   return result;
1027*6236dae4SAndroid Build Coastguard Worker }
1028*6236dae4SAndroid Build Coastguard Worker 
pop3_statemachine(struct Curl_easy * data,struct connectdata * conn)1029*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_statemachine(struct Curl_easy *data,
1030*6236dae4SAndroid Build Coastguard Worker                                   struct connectdata *conn)
1031*6236dae4SAndroid Build Coastguard Worker {
1032*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1033*6236dae4SAndroid Build Coastguard Worker   int pop3code;
1034*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
1035*6236dae4SAndroid Build Coastguard Worker   struct pingpong *pp = &pop3c->pp;
1036*6236dae4SAndroid Build Coastguard Worker   size_t nread = 0;
1037*6236dae4SAndroid Build Coastguard Worker   (void)data;
1038*6236dae4SAndroid Build Coastguard Worker 
1039*6236dae4SAndroid Build Coastguard Worker   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
1040*6236dae4SAndroid Build Coastguard Worker   if(pop3c->state == POP3_UPGRADETLS)
1041*6236dae4SAndroid Build Coastguard Worker     return pop3_perform_upgrade_tls(data, conn);
1042*6236dae4SAndroid Build Coastguard Worker 
1043*6236dae4SAndroid Build Coastguard Worker   /* Flush any data that needs to be sent */
1044*6236dae4SAndroid Build Coastguard Worker   if(pp->sendleft)
1045*6236dae4SAndroid Build Coastguard Worker     return Curl_pp_flushsend(data, pp);
1046*6236dae4SAndroid Build Coastguard Worker 
1047*6236dae4SAndroid Build Coastguard Worker  do {
1048*6236dae4SAndroid Build Coastguard Worker     /* Read the response from the server */
1049*6236dae4SAndroid Build Coastguard Worker    result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &pop3code, &nread);
1050*6236dae4SAndroid Build Coastguard Worker    if(result)
1051*6236dae4SAndroid Build Coastguard Worker      return result;
1052*6236dae4SAndroid Build Coastguard Worker 
1053*6236dae4SAndroid Build Coastguard Worker     if(!pop3code)
1054*6236dae4SAndroid Build Coastguard Worker       break;
1055*6236dae4SAndroid Build Coastguard Worker 
1056*6236dae4SAndroid Build Coastguard Worker     /* We have now received a full POP3 server response */
1057*6236dae4SAndroid Build Coastguard Worker     switch(pop3c->state) {
1058*6236dae4SAndroid Build Coastguard Worker     case POP3_SERVERGREET:
1059*6236dae4SAndroid Build Coastguard Worker       result = pop3_state_servergreet_resp(data, pop3code, pop3c->state);
1060*6236dae4SAndroid Build Coastguard Worker       break;
1061*6236dae4SAndroid Build Coastguard Worker 
1062*6236dae4SAndroid Build Coastguard Worker     case POP3_CAPA:
1063*6236dae4SAndroid Build Coastguard Worker       result = pop3_state_capa_resp(data, pop3code, pop3c->state);
1064*6236dae4SAndroid Build Coastguard Worker       break;
1065*6236dae4SAndroid Build Coastguard Worker 
1066*6236dae4SAndroid Build Coastguard Worker     case POP3_STARTTLS:
1067*6236dae4SAndroid Build Coastguard Worker       result = pop3_state_starttls_resp(data, conn, pop3code, pop3c->state);
1068*6236dae4SAndroid Build Coastguard Worker       break;
1069*6236dae4SAndroid Build Coastguard Worker 
1070*6236dae4SAndroid Build Coastguard Worker     case POP3_AUTH:
1071*6236dae4SAndroid Build Coastguard Worker       result = pop3_state_auth_resp(data, pop3code, pop3c->state);
1072*6236dae4SAndroid Build Coastguard Worker       break;
1073*6236dae4SAndroid Build Coastguard Worker 
1074*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_DIGEST_AUTH
1075*6236dae4SAndroid Build Coastguard Worker     case POP3_APOP:
1076*6236dae4SAndroid Build Coastguard Worker       result = pop3_state_apop_resp(data, pop3code, pop3c->state);
1077*6236dae4SAndroid Build Coastguard Worker       break;
1078*6236dae4SAndroid Build Coastguard Worker #endif
1079*6236dae4SAndroid Build Coastguard Worker 
1080*6236dae4SAndroid Build Coastguard Worker     case POP3_USER:
1081*6236dae4SAndroid Build Coastguard Worker       result = pop3_state_user_resp(data, pop3code, pop3c->state);
1082*6236dae4SAndroid Build Coastguard Worker       break;
1083*6236dae4SAndroid Build Coastguard Worker 
1084*6236dae4SAndroid Build Coastguard Worker     case POP3_PASS:
1085*6236dae4SAndroid Build Coastguard Worker       result = pop3_state_pass_resp(data, pop3code, pop3c->state);
1086*6236dae4SAndroid Build Coastguard Worker       break;
1087*6236dae4SAndroid Build Coastguard Worker 
1088*6236dae4SAndroid Build Coastguard Worker     case POP3_COMMAND:
1089*6236dae4SAndroid Build Coastguard Worker       result = pop3_state_command_resp(data, pop3code, pop3c->state);
1090*6236dae4SAndroid Build Coastguard Worker       break;
1091*6236dae4SAndroid Build Coastguard Worker 
1092*6236dae4SAndroid Build Coastguard Worker     case POP3_QUIT:
1093*6236dae4SAndroid Build Coastguard Worker       pop3_state(data, POP3_STOP);
1094*6236dae4SAndroid Build Coastguard Worker       break;
1095*6236dae4SAndroid Build Coastguard Worker 
1096*6236dae4SAndroid Build Coastguard Worker     default:
1097*6236dae4SAndroid Build Coastguard Worker       /* internal error */
1098*6236dae4SAndroid Build Coastguard Worker       pop3_state(data, POP3_STOP);
1099*6236dae4SAndroid Build Coastguard Worker       break;
1100*6236dae4SAndroid Build Coastguard Worker     }
1101*6236dae4SAndroid Build Coastguard Worker   } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
1102*6236dae4SAndroid Build Coastguard Worker 
1103*6236dae4SAndroid Build Coastguard Worker   return result;
1104*6236dae4SAndroid Build Coastguard Worker }
1105*6236dae4SAndroid Build Coastguard Worker 
1106*6236dae4SAndroid Build Coastguard Worker /* Called repeatedly until done from multi.c */
pop3_multi_statemach(struct Curl_easy * data,bool * done)1107*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done)
1108*6236dae4SAndroid Build Coastguard Worker {
1109*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1110*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1111*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
1112*6236dae4SAndroid Build Coastguard Worker 
1113*6236dae4SAndroid Build Coastguard Worker   if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
1114*6236dae4SAndroid Build Coastguard Worker     bool ssldone = FALSE;
1115*6236dae4SAndroid Build Coastguard Worker     result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
1116*6236dae4SAndroid Build Coastguard Worker     pop3c->ssldone = ssldone;
1117*6236dae4SAndroid Build Coastguard Worker     if(result || !pop3c->ssldone)
1118*6236dae4SAndroid Build Coastguard Worker       return result;
1119*6236dae4SAndroid Build Coastguard Worker   }
1120*6236dae4SAndroid Build Coastguard Worker 
1121*6236dae4SAndroid Build Coastguard Worker   result = Curl_pp_statemach(data, &pop3c->pp, FALSE, FALSE);
1122*6236dae4SAndroid Build Coastguard Worker   *done = (pop3c->state == POP3_STOP);
1123*6236dae4SAndroid Build Coastguard Worker 
1124*6236dae4SAndroid Build Coastguard Worker   return result;
1125*6236dae4SAndroid Build Coastguard Worker }
1126*6236dae4SAndroid Build Coastguard Worker 
pop3_block_statemach(struct Curl_easy * data,struct connectdata * conn,bool disconnecting)1127*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_block_statemach(struct Curl_easy *data,
1128*6236dae4SAndroid Build Coastguard Worker                                      struct connectdata *conn,
1129*6236dae4SAndroid Build Coastguard Worker                                      bool disconnecting)
1130*6236dae4SAndroid Build Coastguard Worker {
1131*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1132*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
1133*6236dae4SAndroid Build Coastguard Worker 
1134*6236dae4SAndroid Build Coastguard Worker   while(pop3c->state != POP3_STOP && !result)
1135*6236dae4SAndroid Build Coastguard Worker     result = Curl_pp_statemach(data, &pop3c->pp, TRUE, disconnecting);
1136*6236dae4SAndroid Build Coastguard Worker 
1137*6236dae4SAndroid Build Coastguard Worker   return result;
1138*6236dae4SAndroid Build Coastguard Worker }
1139*6236dae4SAndroid Build Coastguard Worker 
1140*6236dae4SAndroid Build Coastguard Worker /* Allocate and initialize the POP3 struct for the current Curl_easy if
1141*6236dae4SAndroid Build Coastguard Worker    required */
pop3_init(struct Curl_easy * data)1142*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_init(struct Curl_easy *data)
1143*6236dae4SAndroid Build Coastguard Worker {
1144*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1145*6236dae4SAndroid Build Coastguard Worker   struct POP3 *pop3;
1146*6236dae4SAndroid Build Coastguard Worker 
1147*6236dae4SAndroid Build Coastguard Worker   pop3 = data->req.p.pop3 = calloc(1, sizeof(struct POP3));
1148*6236dae4SAndroid Build Coastguard Worker   if(!pop3)
1149*6236dae4SAndroid Build Coastguard Worker     result = CURLE_OUT_OF_MEMORY;
1150*6236dae4SAndroid Build Coastguard Worker 
1151*6236dae4SAndroid Build Coastguard Worker   return result;
1152*6236dae4SAndroid Build Coastguard Worker }
1153*6236dae4SAndroid Build Coastguard Worker 
1154*6236dae4SAndroid Build Coastguard Worker /* For the POP3 "protocol connect" and "doing" phases only */
pop3_getsock(struct Curl_easy * data,struct connectdata * conn,curl_socket_t * socks)1155*6236dae4SAndroid Build Coastguard Worker static int pop3_getsock(struct Curl_easy *data,
1156*6236dae4SAndroid Build Coastguard Worker                         struct connectdata *conn, curl_socket_t *socks)
1157*6236dae4SAndroid Build Coastguard Worker {
1158*6236dae4SAndroid Build Coastguard Worker   return Curl_pp_getsock(data, &conn->proto.pop3c.pp, socks);
1159*6236dae4SAndroid Build Coastguard Worker }
1160*6236dae4SAndroid Build Coastguard Worker 
1161*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1162*6236dae4SAndroid Build Coastguard Worker  *
1163*6236dae4SAndroid Build Coastguard Worker  * pop3_connect()
1164*6236dae4SAndroid Build Coastguard Worker  *
1165*6236dae4SAndroid Build Coastguard Worker  * This function should do everything that is to be considered a part of the
1166*6236dae4SAndroid Build Coastguard Worker  * connection phase.
1167*6236dae4SAndroid Build Coastguard Worker  *
1168*6236dae4SAndroid Build Coastguard Worker  * The variable 'done' points to will be TRUE if the protocol-layer connect
1169*6236dae4SAndroid Build Coastguard Worker  * phase is done when this function returns, or FALSE if not.
1170*6236dae4SAndroid Build Coastguard Worker  */
pop3_connect(struct Curl_easy * data,bool * done)1171*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_connect(struct Curl_easy *data, bool *done)
1172*6236dae4SAndroid Build Coastguard Worker {
1173*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1174*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1175*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
1176*6236dae4SAndroid Build Coastguard Worker   struct pingpong *pp = &pop3c->pp;
1177*6236dae4SAndroid Build Coastguard Worker 
1178*6236dae4SAndroid Build Coastguard Worker   *done = FALSE; /* default to not done yet */
1179*6236dae4SAndroid Build Coastguard Worker 
1180*6236dae4SAndroid Build Coastguard Worker   /* We always support persistent connections in POP3 */
1181*6236dae4SAndroid Build Coastguard Worker   connkeep(conn, "POP3 default");
1182*6236dae4SAndroid Build Coastguard Worker 
1183*6236dae4SAndroid Build Coastguard Worker   PINGPONG_SETUP(pp, pop3_statemachine, pop3_endofresp);
1184*6236dae4SAndroid Build Coastguard Worker 
1185*6236dae4SAndroid Build Coastguard Worker   /* Set the default preferred authentication type and mechanism */
1186*6236dae4SAndroid Build Coastguard Worker   pop3c->preftype = POP3_TYPE_ANY;
1187*6236dae4SAndroid Build Coastguard Worker   Curl_sasl_init(&pop3c->sasl, data, &saslpop3);
1188*6236dae4SAndroid Build Coastguard Worker 
1189*6236dae4SAndroid Build Coastguard Worker   /* Initialise the pingpong layer */
1190*6236dae4SAndroid Build Coastguard Worker   Curl_pp_init(pp);
1191*6236dae4SAndroid Build Coastguard Worker 
1192*6236dae4SAndroid Build Coastguard Worker   /* Parse the URL options */
1193*6236dae4SAndroid Build Coastguard Worker   result = pop3_parse_url_options(conn);
1194*6236dae4SAndroid Build Coastguard Worker   if(result)
1195*6236dae4SAndroid Build Coastguard Worker     return result;
1196*6236dae4SAndroid Build Coastguard Worker 
1197*6236dae4SAndroid Build Coastguard Worker   /* Start off waiting for the server greeting response */
1198*6236dae4SAndroid Build Coastguard Worker   pop3_state(data, POP3_SERVERGREET);
1199*6236dae4SAndroid Build Coastguard Worker 
1200*6236dae4SAndroid Build Coastguard Worker   result = pop3_multi_statemach(data, done);
1201*6236dae4SAndroid Build Coastguard Worker 
1202*6236dae4SAndroid Build Coastguard Worker   return result;
1203*6236dae4SAndroid Build Coastguard Worker }
1204*6236dae4SAndroid Build Coastguard Worker 
1205*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1206*6236dae4SAndroid Build Coastguard Worker  *
1207*6236dae4SAndroid Build Coastguard Worker  * pop3_done()
1208*6236dae4SAndroid Build Coastguard Worker  *
1209*6236dae4SAndroid Build Coastguard Worker  * The DONE function. This does what needs to be done after a single DO has
1210*6236dae4SAndroid Build Coastguard Worker  * performed.
1211*6236dae4SAndroid Build Coastguard Worker  *
1212*6236dae4SAndroid Build Coastguard Worker  * Input argument is already checked for validity.
1213*6236dae4SAndroid Build Coastguard Worker  */
pop3_done(struct Curl_easy * data,CURLcode status,bool premature)1214*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_done(struct Curl_easy *data, CURLcode status,
1215*6236dae4SAndroid Build Coastguard Worker                           bool premature)
1216*6236dae4SAndroid Build Coastguard Worker {
1217*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1218*6236dae4SAndroid Build Coastguard Worker   struct POP3 *pop3 = data->req.p.pop3;
1219*6236dae4SAndroid Build Coastguard Worker 
1220*6236dae4SAndroid Build Coastguard Worker   (void)premature;
1221*6236dae4SAndroid Build Coastguard Worker 
1222*6236dae4SAndroid Build Coastguard Worker   if(!pop3)
1223*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
1224*6236dae4SAndroid Build Coastguard Worker 
1225*6236dae4SAndroid Build Coastguard Worker   if(status) {
1226*6236dae4SAndroid Build Coastguard Worker     connclose(data->conn, "POP3 done with bad status");
1227*6236dae4SAndroid Build Coastguard Worker     result = status;         /* use the already set error code */
1228*6236dae4SAndroid Build Coastguard Worker   }
1229*6236dae4SAndroid Build Coastguard Worker 
1230*6236dae4SAndroid Build Coastguard Worker   /* Cleanup our per-request based variables */
1231*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(pop3->id);
1232*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(pop3->custom);
1233*6236dae4SAndroid Build Coastguard Worker 
1234*6236dae4SAndroid Build Coastguard Worker   /* Clear the transfer mode for the next request */
1235*6236dae4SAndroid Build Coastguard Worker   pop3->transfer = PPTRANSFER_BODY;
1236*6236dae4SAndroid Build Coastguard Worker 
1237*6236dae4SAndroid Build Coastguard Worker   return result;
1238*6236dae4SAndroid Build Coastguard Worker }
1239*6236dae4SAndroid Build Coastguard Worker 
1240*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1241*6236dae4SAndroid Build Coastguard Worker  *
1242*6236dae4SAndroid Build Coastguard Worker  * pop3_perform()
1243*6236dae4SAndroid Build Coastguard Worker  *
1244*6236dae4SAndroid Build Coastguard Worker  * This is the actual DO function for POP3. Get a message/listing according to
1245*6236dae4SAndroid Build Coastguard Worker  * the options previously setup.
1246*6236dae4SAndroid Build Coastguard Worker  */
pop3_perform(struct Curl_easy * data,bool * connected,bool * dophase_done)1247*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
1248*6236dae4SAndroid Build Coastguard Worker                              bool *dophase_done)
1249*6236dae4SAndroid Build Coastguard Worker {
1250*6236dae4SAndroid Build Coastguard Worker   /* This is POP3 and no proxy */
1251*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1252*6236dae4SAndroid Build Coastguard Worker   struct POP3 *pop3 = data->req.p.pop3;
1253*6236dae4SAndroid Build Coastguard Worker 
1254*6236dae4SAndroid Build Coastguard Worker   DEBUGF(infof(data, "DO phase starts"));
1255*6236dae4SAndroid Build Coastguard Worker 
1256*6236dae4SAndroid Build Coastguard Worker   if(data->req.no_body) {
1257*6236dae4SAndroid Build Coastguard Worker     /* Requested no body means no transfer */
1258*6236dae4SAndroid Build Coastguard Worker     pop3->transfer = PPTRANSFER_INFO;
1259*6236dae4SAndroid Build Coastguard Worker   }
1260*6236dae4SAndroid Build Coastguard Worker 
1261*6236dae4SAndroid Build Coastguard Worker   *dophase_done = FALSE; /* not done yet */
1262*6236dae4SAndroid Build Coastguard Worker 
1263*6236dae4SAndroid Build Coastguard Worker   /* Start the first command in the DO phase */
1264*6236dae4SAndroid Build Coastguard Worker   result = pop3_perform_command(data);
1265*6236dae4SAndroid Build Coastguard Worker   if(result)
1266*6236dae4SAndroid Build Coastguard Worker     return result;
1267*6236dae4SAndroid Build Coastguard Worker 
1268*6236dae4SAndroid Build Coastguard Worker   /* Run the state-machine */
1269*6236dae4SAndroid Build Coastguard Worker   result = pop3_multi_statemach(data, dophase_done);
1270*6236dae4SAndroid Build Coastguard Worker   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
1271*6236dae4SAndroid Build Coastguard Worker 
1272*6236dae4SAndroid Build Coastguard Worker   if(*dophase_done)
1273*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "DO phase is complete"));
1274*6236dae4SAndroid Build Coastguard Worker 
1275*6236dae4SAndroid Build Coastguard Worker   return result;
1276*6236dae4SAndroid Build Coastguard Worker }
1277*6236dae4SAndroid Build Coastguard Worker 
1278*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1279*6236dae4SAndroid Build Coastguard Worker  *
1280*6236dae4SAndroid Build Coastguard Worker  * pop3_do()
1281*6236dae4SAndroid Build Coastguard Worker  *
1282*6236dae4SAndroid Build Coastguard Worker  * This function is registered as 'curl_do' function. It decodes the path
1283*6236dae4SAndroid Build Coastguard Worker  * parts etc as a wrapper to the actual DO function (pop3_perform).
1284*6236dae4SAndroid Build Coastguard Worker  *
1285*6236dae4SAndroid Build Coastguard Worker  * The input argument is already checked for validity.
1286*6236dae4SAndroid Build Coastguard Worker  */
pop3_do(struct Curl_easy * data,bool * done)1287*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_do(struct Curl_easy *data, bool *done)
1288*6236dae4SAndroid Build Coastguard Worker {
1289*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1290*6236dae4SAndroid Build Coastguard Worker   *done = FALSE; /* default to false */
1291*6236dae4SAndroid Build Coastguard Worker 
1292*6236dae4SAndroid Build Coastguard Worker   /* Parse the URL path */
1293*6236dae4SAndroid Build Coastguard Worker   result = pop3_parse_url_path(data);
1294*6236dae4SAndroid Build Coastguard Worker   if(result)
1295*6236dae4SAndroid Build Coastguard Worker     return result;
1296*6236dae4SAndroid Build Coastguard Worker 
1297*6236dae4SAndroid Build Coastguard Worker   /* Parse the custom request */
1298*6236dae4SAndroid Build Coastguard Worker   result = pop3_parse_custom_request(data);
1299*6236dae4SAndroid Build Coastguard Worker   if(result)
1300*6236dae4SAndroid Build Coastguard Worker     return result;
1301*6236dae4SAndroid Build Coastguard Worker 
1302*6236dae4SAndroid Build Coastguard Worker   result = pop3_regular_transfer(data, done);
1303*6236dae4SAndroid Build Coastguard Worker 
1304*6236dae4SAndroid Build Coastguard Worker   return result;
1305*6236dae4SAndroid Build Coastguard Worker }
1306*6236dae4SAndroid Build Coastguard Worker 
1307*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1308*6236dae4SAndroid Build Coastguard Worker  *
1309*6236dae4SAndroid Build Coastguard Worker  * pop3_disconnect()
1310*6236dae4SAndroid Build Coastguard Worker  *
1311*6236dae4SAndroid Build Coastguard Worker  * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
1312*6236dae4SAndroid Build Coastguard Worker  * resources. BLOCKING.
1313*6236dae4SAndroid Build Coastguard Worker  */
pop3_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)1314*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_disconnect(struct Curl_easy *data,
1315*6236dae4SAndroid Build Coastguard Worker                                 struct connectdata *conn, bool dead_connection)
1316*6236dae4SAndroid Build Coastguard Worker {
1317*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
1318*6236dae4SAndroid Build Coastguard Worker   (void)data;
1319*6236dae4SAndroid Build Coastguard Worker 
1320*6236dae4SAndroid Build Coastguard Worker   /* We cannot send quit unconditionally. If this connection is stale or
1321*6236dae4SAndroid Build Coastguard Worker      bad in any way, sending quit and waiting around here will make the
1322*6236dae4SAndroid Build Coastguard Worker      disconnect wait in vain and cause more problems than we need to. */
1323*6236dae4SAndroid Build Coastguard Worker 
1324*6236dae4SAndroid Build Coastguard Worker   if(!dead_connection && conn->bits.protoconnstart) {
1325*6236dae4SAndroid Build Coastguard Worker     if(!pop3_perform_quit(data, conn))
1326*6236dae4SAndroid Build Coastguard Worker       (void)pop3_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */
1327*6236dae4SAndroid Build Coastguard Worker   }
1328*6236dae4SAndroid Build Coastguard Worker 
1329*6236dae4SAndroid Build Coastguard Worker   /* Disconnect from the server */
1330*6236dae4SAndroid Build Coastguard Worker   Curl_pp_disconnect(&pop3c->pp);
1331*6236dae4SAndroid Build Coastguard Worker 
1332*6236dae4SAndroid Build Coastguard Worker   /* Cleanup the SASL module */
1333*6236dae4SAndroid Build Coastguard Worker   Curl_sasl_cleanup(conn, pop3c->sasl.authused);
1334*6236dae4SAndroid Build Coastguard Worker 
1335*6236dae4SAndroid Build Coastguard Worker   /* Cleanup our connection based variables */
1336*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(pop3c->apoptimestamp);
1337*6236dae4SAndroid Build Coastguard Worker 
1338*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1339*6236dae4SAndroid Build Coastguard Worker }
1340*6236dae4SAndroid Build Coastguard Worker 
1341*6236dae4SAndroid Build Coastguard Worker /* Call this when the DO phase has completed */
pop3_dophase_done(struct Curl_easy * data,bool connected)1342*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_dophase_done(struct Curl_easy *data, bool connected)
1343*6236dae4SAndroid Build Coastguard Worker {
1344*6236dae4SAndroid Build Coastguard Worker   (void)data;
1345*6236dae4SAndroid Build Coastguard Worker   (void)connected;
1346*6236dae4SAndroid Build Coastguard Worker 
1347*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1348*6236dae4SAndroid Build Coastguard Worker }
1349*6236dae4SAndroid Build Coastguard Worker 
1350*6236dae4SAndroid Build Coastguard Worker /* Called from multi.c while DOing */
pop3_doing(struct Curl_easy * data,bool * dophase_done)1351*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done)
1352*6236dae4SAndroid Build Coastguard Worker {
1353*6236dae4SAndroid Build Coastguard Worker   CURLcode result = pop3_multi_statemach(data, dophase_done);
1354*6236dae4SAndroid Build Coastguard Worker 
1355*6236dae4SAndroid Build Coastguard Worker   if(result)
1356*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "DO phase failed"));
1357*6236dae4SAndroid Build Coastguard Worker   else if(*dophase_done) {
1358*6236dae4SAndroid Build Coastguard Worker     result = pop3_dophase_done(data, FALSE /* not connected */);
1359*6236dae4SAndroid Build Coastguard Worker 
1360*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "DO phase is complete"));
1361*6236dae4SAndroid Build Coastguard Worker   }
1362*6236dae4SAndroid Build Coastguard Worker 
1363*6236dae4SAndroid Build Coastguard Worker   return result;
1364*6236dae4SAndroid Build Coastguard Worker }
1365*6236dae4SAndroid Build Coastguard Worker 
1366*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1367*6236dae4SAndroid Build Coastguard Worker  *
1368*6236dae4SAndroid Build Coastguard Worker  * pop3_regular_transfer()
1369*6236dae4SAndroid Build Coastguard Worker  *
1370*6236dae4SAndroid Build Coastguard Worker  * The input argument is already checked for validity.
1371*6236dae4SAndroid Build Coastguard Worker  *
1372*6236dae4SAndroid Build Coastguard Worker  * Performs all commands done before a regular transfer between a local and a
1373*6236dae4SAndroid Build Coastguard Worker  * remote host.
1374*6236dae4SAndroid Build Coastguard Worker  */
pop3_regular_transfer(struct Curl_easy * data,bool * dophase_done)1375*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_regular_transfer(struct Curl_easy *data,
1376*6236dae4SAndroid Build Coastguard Worker                                       bool *dophase_done)
1377*6236dae4SAndroid Build Coastguard Worker {
1378*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1379*6236dae4SAndroid Build Coastguard Worker   bool connected = FALSE;
1380*6236dae4SAndroid Build Coastguard Worker 
1381*6236dae4SAndroid Build Coastguard Worker   /* Make sure size is unknown at this point */
1382*6236dae4SAndroid Build Coastguard Worker   data->req.size = -1;
1383*6236dae4SAndroid Build Coastguard Worker 
1384*6236dae4SAndroid Build Coastguard Worker   /* Set the progress data */
1385*6236dae4SAndroid Build Coastguard Worker   Curl_pgrsSetUploadCounter(data, 0);
1386*6236dae4SAndroid Build Coastguard Worker   Curl_pgrsSetDownloadCounter(data, 0);
1387*6236dae4SAndroid Build Coastguard Worker   Curl_pgrsSetUploadSize(data, -1);
1388*6236dae4SAndroid Build Coastguard Worker   Curl_pgrsSetDownloadSize(data, -1);
1389*6236dae4SAndroid Build Coastguard Worker 
1390*6236dae4SAndroid Build Coastguard Worker   /* Carry out the perform */
1391*6236dae4SAndroid Build Coastguard Worker   result = pop3_perform(data, &connected, dophase_done);
1392*6236dae4SAndroid Build Coastguard Worker 
1393*6236dae4SAndroid Build Coastguard Worker   /* Perform post DO phase operations if necessary */
1394*6236dae4SAndroid Build Coastguard Worker   if(!result && *dophase_done)
1395*6236dae4SAndroid Build Coastguard Worker     result = pop3_dophase_done(data, connected);
1396*6236dae4SAndroid Build Coastguard Worker 
1397*6236dae4SAndroid Build Coastguard Worker   return result;
1398*6236dae4SAndroid Build Coastguard Worker }
1399*6236dae4SAndroid Build Coastguard Worker 
pop3_setup_connection(struct Curl_easy * data,struct connectdata * conn)1400*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_setup_connection(struct Curl_easy *data,
1401*6236dae4SAndroid Build Coastguard Worker                                       struct connectdata *conn)
1402*6236dae4SAndroid Build Coastguard Worker {
1403*6236dae4SAndroid Build Coastguard Worker   /* Initialise the POP3 layer */
1404*6236dae4SAndroid Build Coastguard Worker   CURLcode result = pop3_init(data);
1405*6236dae4SAndroid Build Coastguard Worker   if(result)
1406*6236dae4SAndroid Build Coastguard Worker     return result;
1407*6236dae4SAndroid Build Coastguard Worker 
1408*6236dae4SAndroid Build Coastguard Worker   /* Clear the TLS upgraded flag */
1409*6236dae4SAndroid Build Coastguard Worker   conn->bits.tls_upgraded = FALSE;
1410*6236dae4SAndroid Build Coastguard Worker 
1411*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1412*6236dae4SAndroid Build Coastguard Worker }
1413*6236dae4SAndroid Build Coastguard Worker 
1414*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1415*6236dae4SAndroid Build Coastguard Worker  *
1416*6236dae4SAndroid Build Coastguard Worker  * pop3_parse_url_options()
1417*6236dae4SAndroid Build Coastguard Worker  *
1418*6236dae4SAndroid Build Coastguard Worker  * Parse the URL login options.
1419*6236dae4SAndroid Build Coastguard Worker  */
pop3_parse_url_options(struct connectdata * conn)1420*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_parse_url_options(struct connectdata *conn)
1421*6236dae4SAndroid Build Coastguard Worker {
1422*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1423*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
1424*6236dae4SAndroid Build Coastguard Worker   const char *ptr = conn->options;
1425*6236dae4SAndroid Build Coastguard Worker 
1426*6236dae4SAndroid Build Coastguard Worker   while(!result && ptr && *ptr) {
1427*6236dae4SAndroid Build Coastguard Worker     const char *key = ptr;
1428*6236dae4SAndroid Build Coastguard Worker     const char *value;
1429*6236dae4SAndroid Build Coastguard Worker 
1430*6236dae4SAndroid Build Coastguard Worker     while(*ptr && *ptr != '=')
1431*6236dae4SAndroid Build Coastguard Worker       ptr++;
1432*6236dae4SAndroid Build Coastguard Worker 
1433*6236dae4SAndroid Build Coastguard Worker     value = ptr + 1;
1434*6236dae4SAndroid Build Coastguard Worker 
1435*6236dae4SAndroid Build Coastguard Worker     while(*ptr && *ptr != ';')
1436*6236dae4SAndroid Build Coastguard Worker       ptr++;
1437*6236dae4SAndroid Build Coastguard Worker 
1438*6236dae4SAndroid Build Coastguard Worker     if(strncasecompare(key, "AUTH=", 5)) {
1439*6236dae4SAndroid Build Coastguard Worker       result = Curl_sasl_parse_url_auth_option(&pop3c->sasl,
1440*6236dae4SAndroid Build Coastguard Worker                                                value, ptr - value);
1441*6236dae4SAndroid Build Coastguard Worker 
1442*6236dae4SAndroid Build Coastguard Worker       if(result && strncasecompare(value, "+APOP", ptr - value)) {
1443*6236dae4SAndroid Build Coastguard Worker         pop3c->preftype = POP3_TYPE_APOP;
1444*6236dae4SAndroid Build Coastguard Worker         pop3c->sasl.prefmech = SASL_AUTH_NONE;
1445*6236dae4SAndroid Build Coastguard Worker         result = CURLE_OK;
1446*6236dae4SAndroid Build Coastguard Worker       }
1447*6236dae4SAndroid Build Coastguard Worker     }
1448*6236dae4SAndroid Build Coastguard Worker     else
1449*6236dae4SAndroid Build Coastguard Worker       result = CURLE_URL_MALFORMAT;
1450*6236dae4SAndroid Build Coastguard Worker 
1451*6236dae4SAndroid Build Coastguard Worker     if(*ptr == ';')
1452*6236dae4SAndroid Build Coastguard Worker       ptr++;
1453*6236dae4SAndroid Build Coastguard Worker   }
1454*6236dae4SAndroid Build Coastguard Worker 
1455*6236dae4SAndroid Build Coastguard Worker   if(pop3c->preftype != POP3_TYPE_APOP)
1456*6236dae4SAndroid Build Coastguard Worker     switch(pop3c->sasl.prefmech) {
1457*6236dae4SAndroid Build Coastguard Worker     case SASL_AUTH_NONE:
1458*6236dae4SAndroid Build Coastguard Worker       pop3c->preftype = POP3_TYPE_NONE;
1459*6236dae4SAndroid Build Coastguard Worker       break;
1460*6236dae4SAndroid Build Coastguard Worker     case SASL_AUTH_DEFAULT:
1461*6236dae4SAndroid Build Coastguard Worker       pop3c->preftype = POP3_TYPE_ANY;
1462*6236dae4SAndroid Build Coastguard Worker       break;
1463*6236dae4SAndroid Build Coastguard Worker     default:
1464*6236dae4SAndroid Build Coastguard Worker       pop3c->preftype = POP3_TYPE_SASL;
1465*6236dae4SAndroid Build Coastguard Worker       break;
1466*6236dae4SAndroid Build Coastguard Worker     }
1467*6236dae4SAndroid Build Coastguard Worker 
1468*6236dae4SAndroid Build Coastguard Worker   return result;
1469*6236dae4SAndroid Build Coastguard Worker }
1470*6236dae4SAndroid Build Coastguard Worker 
1471*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1472*6236dae4SAndroid Build Coastguard Worker  *
1473*6236dae4SAndroid Build Coastguard Worker  * pop3_parse_url_path()
1474*6236dae4SAndroid Build Coastguard Worker  *
1475*6236dae4SAndroid Build Coastguard Worker  * Parse the URL path into separate path components.
1476*6236dae4SAndroid Build Coastguard Worker  */
pop3_parse_url_path(struct Curl_easy * data)1477*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_parse_url_path(struct Curl_easy *data)
1478*6236dae4SAndroid Build Coastguard Worker {
1479*6236dae4SAndroid Build Coastguard Worker   /* The POP3 struct is already initialised in pop3_connect() */
1480*6236dae4SAndroid Build Coastguard Worker   struct POP3 *pop3 = data->req.p.pop3;
1481*6236dae4SAndroid Build Coastguard Worker   const char *path = &data->state.up.path[1]; /* skip leading path */
1482*6236dae4SAndroid Build Coastguard Worker 
1483*6236dae4SAndroid Build Coastguard Worker   /* URL decode the path for the message ID */
1484*6236dae4SAndroid Build Coastguard Worker   return Curl_urldecode(path, 0, &pop3->id, NULL, REJECT_CTRL);
1485*6236dae4SAndroid Build Coastguard Worker }
1486*6236dae4SAndroid Build Coastguard Worker 
1487*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1488*6236dae4SAndroid Build Coastguard Worker  *
1489*6236dae4SAndroid Build Coastguard Worker  * pop3_parse_custom_request()
1490*6236dae4SAndroid Build Coastguard Worker  *
1491*6236dae4SAndroid Build Coastguard Worker  * Parse the custom request.
1492*6236dae4SAndroid Build Coastguard Worker  */
pop3_parse_custom_request(struct Curl_easy * data)1493*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_parse_custom_request(struct Curl_easy *data)
1494*6236dae4SAndroid Build Coastguard Worker {
1495*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1496*6236dae4SAndroid Build Coastguard Worker   struct POP3 *pop3 = data->req.p.pop3;
1497*6236dae4SAndroid Build Coastguard Worker   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
1498*6236dae4SAndroid Build Coastguard Worker 
1499*6236dae4SAndroid Build Coastguard Worker   /* URL decode the custom request */
1500*6236dae4SAndroid Build Coastguard Worker   if(custom)
1501*6236dae4SAndroid Build Coastguard Worker     result = Curl_urldecode(custom, 0, &pop3->custom, NULL, REJECT_CTRL);
1502*6236dae4SAndroid Build Coastguard Worker 
1503*6236dae4SAndroid Build Coastguard Worker   return result;
1504*6236dae4SAndroid Build Coastguard Worker }
1505*6236dae4SAndroid Build Coastguard Worker 
1506*6236dae4SAndroid Build Coastguard Worker /***********************************************************************
1507*6236dae4SAndroid Build Coastguard Worker  *
1508*6236dae4SAndroid Build Coastguard Worker  * pop3_write()
1509*6236dae4SAndroid Build Coastguard Worker  *
1510*6236dae4SAndroid Build Coastguard Worker  * This function scans the body after the end-of-body and writes everything
1511*6236dae4SAndroid Build Coastguard Worker  * until the end is found.
1512*6236dae4SAndroid Build Coastguard Worker  */
pop3_write(struct Curl_easy * data,const char * str,size_t nread,bool is_eos)1513*6236dae4SAndroid Build Coastguard Worker static CURLcode pop3_write(struct Curl_easy *data, const char *str,
1514*6236dae4SAndroid Build Coastguard Worker                            size_t nread, bool is_eos)
1515*6236dae4SAndroid Build Coastguard Worker {
1516*6236dae4SAndroid Build Coastguard Worker   /* This code could be made into a special function in the handler struct */
1517*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
1518*6236dae4SAndroid Build Coastguard Worker   struct SingleRequest *k = &data->req;
1519*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
1520*6236dae4SAndroid Build Coastguard Worker   struct pop3_conn *pop3c = &conn->proto.pop3c;
1521*6236dae4SAndroid Build Coastguard Worker   bool strip_dot = FALSE;
1522*6236dae4SAndroid Build Coastguard Worker   size_t last = 0;
1523*6236dae4SAndroid Build Coastguard Worker   size_t i;
1524*6236dae4SAndroid Build Coastguard Worker   (void)is_eos;
1525*6236dae4SAndroid Build Coastguard Worker 
1526*6236dae4SAndroid Build Coastguard Worker   /* Search through the buffer looking for the end-of-body marker which is
1527*6236dae4SAndroid Build Coastguard Worker      5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
1528*6236dae4SAndroid Build Coastguard Worker      the eob so the server will have prefixed it with an extra dot which we
1529*6236dae4SAndroid Build Coastguard Worker      need to strip out. Additionally the marker could of course be spread out
1530*6236dae4SAndroid Build Coastguard Worker      over 5 different data chunks. */
1531*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < nread; i++) {
1532*6236dae4SAndroid Build Coastguard Worker     size_t prev = pop3c->eob;
1533*6236dae4SAndroid Build Coastguard Worker 
1534*6236dae4SAndroid Build Coastguard Worker     switch(str[i]) {
1535*6236dae4SAndroid Build Coastguard Worker     case 0x0d:
1536*6236dae4SAndroid Build Coastguard Worker       if(pop3c->eob == 0) {
1537*6236dae4SAndroid Build Coastguard Worker         pop3c->eob++;
1538*6236dae4SAndroid Build Coastguard Worker 
1539*6236dae4SAndroid Build Coastguard Worker         if(i) {
1540*6236dae4SAndroid Build Coastguard Worker           /* Write out the body part that did not match */
1541*6236dae4SAndroid Build Coastguard Worker           result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
1542*6236dae4SAndroid Build Coastguard Worker                                      i - last);
1543*6236dae4SAndroid Build Coastguard Worker 
1544*6236dae4SAndroid Build Coastguard Worker           if(result)
1545*6236dae4SAndroid Build Coastguard Worker             return result;
1546*6236dae4SAndroid Build Coastguard Worker 
1547*6236dae4SAndroid Build Coastguard Worker           last = i;
1548*6236dae4SAndroid Build Coastguard Worker         }
1549*6236dae4SAndroid Build Coastguard Worker       }
1550*6236dae4SAndroid Build Coastguard Worker       else if(pop3c->eob == 3)
1551*6236dae4SAndroid Build Coastguard Worker         pop3c->eob++;
1552*6236dae4SAndroid Build Coastguard Worker       else
1553*6236dae4SAndroid Build Coastguard Worker         /* If the character match was not at position 0 or 3 then restart the
1554*6236dae4SAndroid Build Coastguard Worker            pattern matching */
1555*6236dae4SAndroid Build Coastguard Worker         pop3c->eob = 1;
1556*6236dae4SAndroid Build Coastguard Worker       break;
1557*6236dae4SAndroid Build Coastguard Worker 
1558*6236dae4SAndroid Build Coastguard Worker     case 0x0a:
1559*6236dae4SAndroid Build Coastguard Worker       if(pop3c->eob == 1 || pop3c->eob == 4)
1560*6236dae4SAndroid Build Coastguard Worker         pop3c->eob++;
1561*6236dae4SAndroid Build Coastguard Worker       else
1562*6236dae4SAndroid Build Coastguard Worker         /* If the character match was not at position 1 or 4 then start the
1563*6236dae4SAndroid Build Coastguard Worker            search again */
1564*6236dae4SAndroid Build Coastguard Worker         pop3c->eob = 0;
1565*6236dae4SAndroid Build Coastguard Worker       break;
1566*6236dae4SAndroid Build Coastguard Worker 
1567*6236dae4SAndroid Build Coastguard Worker     case 0x2e:
1568*6236dae4SAndroid Build Coastguard Worker       if(pop3c->eob == 2)
1569*6236dae4SAndroid Build Coastguard Worker         pop3c->eob++;
1570*6236dae4SAndroid Build Coastguard Worker       else if(pop3c->eob == 3) {
1571*6236dae4SAndroid Build Coastguard Worker         /* We have an extra dot after the CRLF which we need to strip off */
1572*6236dae4SAndroid Build Coastguard Worker         strip_dot = TRUE;
1573*6236dae4SAndroid Build Coastguard Worker         pop3c->eob = 0;
1574*6236dae4SAndroid Build Coastguard Worker       }
1575*6236dae4SAndroid Build Coastguard Worker       else
1576*6236dae4SAndroid Build Coastguard Worker         /* If the character match was not at position 2 then start the search
1577*6236dae4SAndroid Build Coastguard Worker            again */
1578*6236dae4SAndroid Build Coastguard Worker         pop3c->eob = 0;
1579*6236dae4SAndroid Build Coastguard Worker       break;
1580*6236dae4SAndroid Build Coastguard Worker 
1581*6236dae4SAndroid Build Coastguard Worker     default:
1582*6236dae4SAndroid Build Coastguard Worker       pop3c->eob = 0;
1583*6236dae4SAndroid Build Coastguard Worker       break;
1584*6236dae4SAndroid Build Coastguard Worker     }
1585*6236dae4SAndroid Build Coastguard Worker 
1586*6236dae4SAndroid Build Coastguard Worker     /* Did we have a partial match which has subsequently failed? */
1587*6236dae4SAndroid Build Coastguard Worker     if(prev && prev >= pop3c->eob) {
1588*6236dae4SAndroid Build Coastguard Worker       /* Strip can only be non-zero for the very first mismatch after CRLF
1589*6236dae4SAndroid Build Coastguard Worker          and then both prev and strip are equal and nothing will be output
1590*6236dae4SAndroid Build Coastguard Worker          below */
1591*6236dae4SAndroid Build Coastguard Worker       while(prev && pop3c->strip) {
1592*6236dae4SAndroid Build Coastguard Worker         prev--;
1593*6236dae4SAndroid Build Coastguard Worker         pop3c->strip--;
1594*6236dae4SAndroid Build Coastguard Worker       }
1595*6236dae4SAndroid Build Coastguard Worker 
1596*6236dae4SAndroid Build Coastguard Worker       if(prev) {
1597*6236dae4SAndroid Build Coastguard Worker         /* If the partial match was the CRLF and dot then only write the CRLF
1598*6236dae4SAndroid Build Coastguard Worker            as the server would have inserted the dot */
1599*6236dae4SAndroid Build Coastguard Worker         if(strip_dot && prev - 1 > 0) {
1600*6236dae4SAndroid Build Coastguard Worker           result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
1601*6236dae4SAndroid Build Coastguard Worker                                      prev - 1);
1602*6236dae4SAndroid Build Coastguard Worker         }
1603*6236dae4SAndroid Build Coastguard Worker         else if(!strip_dot) {
1604*6236dae4SAndroid Build Coastguard Worker           result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
1605*6236dae4SAndroid Build Coastguard Worker                                      prev);
1606*6236dae4SAndroid Build Coastguard Worker         }
1607*6236dae4SAndroid Build Coastguard Worker         else {
1608*6236dae4SAndroid Build Coastguard Worker           result = CURLE_OK;
1609*6236dae4SAndroid Build Coastguard Worker         }
1610*6236dae4SAndroid Build Coastguard Worker 
1611*6236dae4SAndroid Build Coastguard Worker         if(result)
1612*6236dae4SAndroid Build Coastguard Worker           return result;
1613*6236dae4SAndroid Build Coastguard Worker 
1614*6236dae4SAndroid Build Coastguard Worker         last = i;
1615*6236dae4SAndroid Build Coastguard Worker         strip_dot = FALSE;
1616*6236dae4SAndroid Build Coastguard Worker       }
1617*6236dae4SAndroid Build Coastguard Worker     }
1618*6236dae4SAndroid Build Coastguard Worker   }
1619*6236dae4SAndroid Build Coastguard Worker 
1620*6236dae4SAndroid Build Coastguard Worker   if(pop3c->eob == POP3_EOB_LEN) {
1621*6236dae4SAndroid Build Coastguard Worker     /* We have a full match so the transfer is done, however we must transfer
1622*6236dae4SAndroid Build Coastguard Worker     the CRLF at the start of the EOB as this is considered to be part of the
1623*6236dae4SAndroid Build Coastguard Worker     message as per RFC-1939, sect. 3 */
1624*6236dae4SAndroid Build Coastguard Worker     result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
1625*6236dae4SAndroid Build Coastguard Worker 
1626*6236dae4SAndroid Build Coastguard Worker     k->keepon &= ~KEEP_RECV;
1627*6236dae4SAndroid Build Coastguard Worker     pop3c->eob = 0;
1628*6236dae4SAndroid Build Coastguard Worker 
1629*6236dae4SAndroid Build Coastguard Worker     return result;
1630*6236dae4SAndroid Build Coastguard Worker   }
1631*6236dae4SAndroid Build Coastguard Worker 
1632*6236dae4SAndroid Build Coastguard Worker   if(pop3c->eob)
1633*6236dae4SAndroid Build Coastguard Worker     /* While EOB is matching nothing should be output */
1634*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
1635*6236dae4SAndroid Build Coastguard Worker 
1636*6236dae4SAndroid Build Coastguard Worker   if(nread - last) {
1637*6236dae4SAndroid Build Coastguard Worker     result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
1638*6236dae4SAndroid Build Coastguard Worker                                nread - last);
1639*6236dae4SAndroid Build Coastguard Worker   }
1640*6236dae4SAndroid Build Coastguard Worker 
1641*6236dae4SAndroid Build Coastguard Worker   return result;
1642*6236dae4SAndroid Build Coastguard Worker }
1643*6236dae4SAndroid Build Coastguard Worker 
1644*6236dae4SAndroid Build Coastguard Worker #endif /* CURL_DISABLE_POP3 */
1645