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