blob: 78f6afef1f4cfc66fd008189e3a986ff74db37ed [file] [log] [blame]
Kristian Monsen5ab50182010-05-14 18:53:44 +01001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Elliott Hughes0128fe42018-02-27 14:57:55 -08008 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
Kristian Monsen5ab50182010-05-14 18:53:44 +01009 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
Alex Deymod15eaac2016-06-28 14:49:26 -070012 * are also available at https://curl.haxx.se/docs/copyright.html.
Kristian Monsen5ab50182010-05-14 18:53:44 +010013 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070021 * RFC1734 POP3 Authentication
Kristian Monsen5ab50182010-05-14 18:53:44 +010022 * RFC1939 POP3 protocol
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070023 * RFC2195 CRAM-MD5 authentication
Kristian Monsen5ab50182010-05-14 18:53:44 +010024 * RFC2384 POP URL Scheme
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070025 * RFC2449 POP3 Extension Mechanism
Kristian Monsen5ab50182010-05-14 18:53:44 +010026 * RFC2595 Using TLS with IMAP, POP3 and ACAP
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070027 * RFC2831 DIGEST-MD5 authentication
28 * RFC4422 Simple Authentication and Security Layer (SASL)
29 * RFC4616 PLAIN authentication
30 * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
31 * RFC5034 POP3 SASL Authentication Mechanism
32 * RFC6749 OAuth 2.0 Authorization Framework
33 * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
Kristian Monsen5ab50182010-05-14 18:53:44 +010034 *
35 ***************************************************************************/
36
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070037#include "curl_setup.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010038
39#ifndef CURL_DISABLE_POP3
Kristian Monsen5ab50182010-05-14 18:53:44 +010040
Kristian Monsen5ab50182010-05-14 18:53:44 +010041#ifdef HAVE_NETINET_IN_H
42#include <netinet/in.h>
43#endif
44#ifdef HAVE_ARPA_INET_H
45#include <arpa/inet.h>
46#endif
47#ifdef HAVE_UTSNAME_H
48#include <sys/utsname.h>
49#endif
50#ifdef HAVE_NETDB_H
51#include <netdb.h>
52#endif
53#ifdef __VMS
54#include <in.h>
55#include <inet.h>
56#endif
57
58#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
59#undef in_addr_t
60#define in_addr_t unsigned long
61#endif
62
63#include <curl/curl.h>
64#include "urldata.h"
65#include "sendf.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010066#include "hostip.h"
67#include "progress.h"
68#include "transfer.h"
69#include "escape.h"
70#include "http.h" /* for HTTP proxy tunnel stuff */
71#include "socks.h"
72#include "pop3.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010073#include "strtoofft.h"
Elliott Hughescee03382017-06-23 12:17:18 -070074#include "strcase.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070075#include "vtls/vtls.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010076#include "connect.h"
77#include "strerror.h"
78#include "select.h"
79#include "multiif.h"
80#include "url.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070081#include "curl_sasl.h"
82#include "curl_md5.h"
83#include "warnless.h"
Alex Deymod15eaac2016-06-28 14:49:26 -070084/* The last 3 #include files should be in this order */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070085#include "curl_printf.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010086#include "curl_memory.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010087#include "memdebug.h"
88
89/* Local API functions */
Kristian Monsen5ab50182010-05-14 18:53:44 +010090static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
91static CURLcode pop3_do(struct connectdata *conn, bool *done);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070092static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
93 bool premature);
Kristian Monsen5ab50182010-05-14 18:53:44 +010094static CURLcode pop3_connect(struct connectdata *conn, bool *done);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070095static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
Kristian Monsen5ab50182010-05-14 18:53:44 +010096static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070097static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
Kristian Monsen5ab50182010-05-14 18:53:44 +010098 int numsocks);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070099static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
100static CURLcode pop3_setup_connection(struct connectdata *conn);
101static CURLcode pop3_parse_url_options(struct connectdata *conn);
102static CURLcode pop3_parse_url_path(struct connectdata *conn);
103static CURLcode pop3_parse_custom_request(struct connectdata *conn);
104static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech,
105 const char *initresp);
106static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp);
Elliott Hughescee03382017-06-23 12:17:18 -0700107static void pop3_get_message(char *buffer, char **outptr);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100108
109/*
110 * POP3 protocol handler.
111 */
112
113const struct Curl_handler Curl_handler_pop3 = {
114 "POP3", /* scheme */
115 pop3_setup_connection, /* setup_connection */
116 pop3_do, /* do_it */
117 pop3_done, /* done */
118 ZERO_NULL, /* do_more */
119 pop3_connect, /* connect_it */
120 pop3_multi_statemach, /* connecting */
121 pop3_doing, /* doing */
122 pop3_getsock, /* proto_getsock */
123 pop3_getsock, /* doing_getsock */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700124 ZERO_NULL, /* domore_getsock */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100125 ZERO_NULL, /* perform_getsock */
126 pop3_disconnect, /* disconnect */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700127 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700128 ZERO_NULL, /* connection_check */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100129 PORT_POP3, /* defport */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700130 CURLPROTO_POP3, /* protocol */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700131 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
132 PROTOPT_URLOPTIONS
Kristian Monsen5ab50182010-05-14 18:53:44 +0100133};
134
Kristian Monsen5ab50182010-05-14 18:53:44 +0100135#ifdef USE_SSL
136/*
137 * POP3S protocol handler.
138 */
139
140const struct Curl_handler Curl_handler_pop3s = {
141 "POP3S", /* scheme */
142 pop3_setup_connection, /* setup_connection */
143 pop3_do, /* do_it */
144 pop3_done, /* done */
145 ZERO_NULL, /* do_more */
146 pop3_connect, /* connect_it */
147 pop3_multi_statemach, /* connecting */
148 pop3_doing, /* doing */
149 pop3_getsock, /* proto_getsock */
150 pop3_getsock, /* doing_getsock */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700151 ZERO_NULL, /* domore_getsock */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100152 ZERO_NULL, /* perform_getsock */
153 pop3_disconnect, /* disconnect */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700154 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700155 ZERO_NULL, /* connection_check */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100156 PORT_POP3S, /* defport */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700157 CURLPROTO_POP3S, /* protocol */
158 PROTOPT_CLOSEACTION | PROTOPT_SSL
Elliott Hughes82be86d2017-09-20 17:00:17 -0700159 | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100160};
161#endif
162
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700163/* SASL parameters for the pop3 protocol */
164static const struct SASLproto saslpop3 = {
165 "pop", /* The service name */
Alex Deymod15eaac2016-06-28 14:49:26 -0700166 '*', /* Code received when continuation is expected */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700167 '+', /* Code to receive upon authentication success */
168 255 - 8, /* Maximum initial response length (no max) */
169 pop3_perform_auth, /* Send authentication command */
170 pop3_continue_auth, /* Send authentication continuation */
171 pop3_get_message /* Get SASL response message */
172};
Kristian Monsen5ab50182010-05-14 18:53:44 +0100173
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700174#ifdef USE_SSL
175static void pop3_to_pop3s(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100176{
Alex Deymod15eaac2016-06-28 14:49:26 -0700177 /* Change the connection handler */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700178 conn->handler = &Curl_handler_pop3s;
Alex Deymod15eaac2016-06-28 14:49:26 -0700179
180 /* Set the connection's upgraded to TLS flag */
181 conn->tls_upgraded = TRUE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700182}
183#else
184#define pop3_to_pop3s(x) Curl_nop_stmt
185#endif
Kristian Monsen5ab50182010-05-14 18:53:44 +0100186
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700187/***********************************************************************
188 *
189 * pop3_endofresp()
190 *
191 * Checks for an ending POP3 status code at the start of the given string, but
192 * also detects the APOP timestamp from the server greeting and various
193 * capabilities from the CAPA response including the supported authentication
194 * types and allowed SASL mechanisms.
195 */
196static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
197 int *resp)
198{
199 struct pop3_conn *pop3c = &conn->proto.pop3c;
200
201 /* Do we have an error response? */
202 if(len >= 4 && !memcmp("-ERR", line, 4)) {
203 *resp = '-';
204
Kristian Monsen5ab50182010-05-14 18:53:44 +0100205 return TRUE;
206 }
207
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700208 /* Are we processing CAPA command responses? */
209 if(pop3c->state == POP3_CAPA) {
210 /* Do we have the terminating line? */
211 if(len >= 1 && !memcmp(line, ".", 1))
Alex Deymod15eaac2016-06-28 14:49:26 -0700212 /* Treat the response as a success */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700213 *resp = '+';
214 else
Alex Deymod15eaac2016-06-28 14:49:26 -0700215 /* Treat the response as an untagged continuation */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700216 *resp = '*';
217
218 return TRUE;
219 }
220
Alex Deymod15eaac2016-06-28 14:49:26 -0700221 /* Do we have a success response? */
222 if(len >= 3 && !memcmp("+OK", line, 3)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700223 *resp = '+';
224
225 return TRUE;
226 }
227
Alex Deymod15eaac2016-06-28 14:49:26 -0700228 /* Do we have a continuation response? */
229 if(len >= 1 && !memcmp("+", line, 1)) {
230 *resp = '*';
231
232 return TRUE;
233 }
234
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700235 return FALSE; /* Nothing for us */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100236}
237
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700238/***********************************************************************
239 *
240 * pop3_get_message()
241 *
242 * Gets the authentication message from the response buffer.
243 */
Elliott Hughescee03382017-06-23 12:17:18 -0700244static void pop3_get_message(char *buffer, char **outptr)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100245{
Elliott Hughes0128fe42018-02-27 14:57:55 -0800246 size_t len = strlen(buffer);
Elliott Hughescee03382017-06-23 12:17:18 -0700247 char *message = NULL;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700248
Elliott Hughes0128fe42018-02-27 14:57:55 -0800249 if(len > 2) {
250 /* Find the start of the message */
251 len -= 2;
252 for(message = buffer + 2; *message == ' ' || *message == '\t';
253 message++, len--)
254 ;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700255
Elliott Hughes0128fe42018-02-27 14:57:55 -0800256 /* Find the end of the message */
257 for(; len--;)
258 if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
259 message[len] != '\t')
260 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700261
Elliott Hughes0128fe42018-02-27 14:57:55 -0800262 /* Terminate the message */
263 if(++len) {
264 message[len] = '\0';
265 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700266 }
Elliott Hughes0128fe42018-02-27 14:57:55 -0800267 else
268 /* junk input => zero length output */
269 message = &buffer[len];
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700270
271 *outptr = message;
272}
273
274/***********************************************************************
275 *
276 * state()
277 *
278 * This is the ONLY way to change POP3 state!
279 */
280static void state(struct connectdata *conn, pop3state newstate)
281{
282 struct pop3_conn *pop3c = &conn->proto.pop3c;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100283#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
284 /* for debug purposes */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700285 static const char * const names[] = {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100286 "STOP",
287 "SERVERGREET",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700288 "CAPA",
289 "STARTTLS",
290 "UPGRADETLS",
291 "AUTH",
292 "APOP",
Kristian Monsen5ab50182010-05-14 18:53:44 +0100293 "USER",
294 "PASS",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700295 "COMMAND",
Kristian Monsen5ab50182010-05-14 18:53:44 +0100296 "QUIT",
297 /* LAST */
298 };
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700299
Kristian Monsen5ab50182010-05-14 18:53:44 +0100300 if(pop3c->state != newstate)
301 infof(conn->data, "POP3 %p state change from %s to %s\n",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700302 (void *)pop3c, names[pop3c->state], names[newstate]);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100303#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700304
Kristian Monsen5ab50182010-05-14 18:53:44 +0100305 pop3c->state = newstate;
306}
307
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700308/***********************************************************************
309 *
310 * pop3_perform_capa()
311 *
312 * Sends the CAPA command in order to obtain a list of server side supported
313 * capabilities.
314 */
315static CURLcode pop3_perform_capa(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100316{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700317 CURLcode result = CURLE_OK;
318 struct pop3_conn *pop3c = &conn->proto.pop3c;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100319
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700320 pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
321 pop3c->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */
322 pop3c->tls_supported = FALSE; /* Clear the TLS capability */
323
324 /* Send the CAPA command */
325 result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA");
326
327 if(!result)
328 state(conn, POP3_CAPA);
329
330 return result;
331}
332
333/***********************************************************************
334 *
335 * pop3_perform_starttls()
336 *
337 * Sends the STLS command to start the upgrade to TLS.
338 */
339static CURLcode pop3_perform_starttls(struct connectdata *conn)
340{
341 CURLcode result = CURLE_OK;
342
343 /* Send the STLS command */
344 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS");
345
346 if(!result)
347 state(conn, POP3_STARTTLS);
348
349 return result;
350}
351
352/***********************************************************************
353 *
354 * pop3_perform_upgrade_tls()
355 *
356 * Performs the upgrade to TLS.
357 */
358static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
359{
360 CURLcode result = CURLE_OK;
361 struct pop3_conn *pop3c = &conn->proto.pop3c;
362
363 /* Start the SSL connection */
364 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
365
366 if(!result) {
367 if(pop3c->state != POP3_UPGRADETLS)
368 state(conn, POP3_UPGRADETLS);
369
370 if(pop3c->ssldone) {
371 pop3_to_pop3s(conn);
372 result = pop3_perform_capa(conn);
373 }
374 }
375
376 return result;
377}
378
379/***********************************************************************
380 *
381 * pop3_perform_user()
382 *
383 * Sends a clear text USER command to authenticate with.
384 */
385static CURLcode pop3_perform_user(struct connectdata *conn)
386{
387 CURLcode result = CURLE_OK;
388
389 /* Check we have a username and password to authenticate with and end the
390 connect phase if we don't */
391 if(!conn->bits.user_passwd) {
392 state(conn, POP3_STOP);
393
Kristian Monsen5ab50182010-05-14 18:53:44 +0100394 return result;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700395 }
Kristian Monsen5ab50182010-05-14 18:53:44 +0100396
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700397 /* Send the USER command */
398 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
399 conn->user ? conn->user : "");
400 if(!result)
401 state(conn, POP3_USER);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100402
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700403 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100404}
405
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700406#ifndef CURL_DISABLE_CRYPTO_AUTH
407/***********************************************************************
408 *
409 * pop3_perform_apop()
410 *
411 * Sends an APOP command to authenticate with.
412 */
413static CURLcode pop3_perform_apop(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100414{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700415 CURLcode result = CURLE_OK;
416 struct pop3_conn *pop3c = &conn->proto.pop3c;
417 size_t i;
418 MD5_context *ctxt;
419 unsigned char digest[MD5_DIGEST_LEN];
420 char secret[2 * MD5_DIGEST_LEN + 1];
421
422 /* Check we have a username and password to authenticate with and end the
423 connect phase if we don't */
424 if(!conn->bits.user_passwd) {
425 state(conn, POP3_STOP);
426
427 return result;
428 }
429
430 /* Create the digest */
431 ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
432 if(!ctxt)
433 return CURLE_OUT_OF_MEMORY;
434
435 Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
436 curlx_uztoui(strlen(pop3c->apoptimestamp)));
437
438 Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
439 curlx_uztoui(strlen(conn->passwd)));
440
441 /* Finalise the digest */
442 Curl_MD5_final(ctxt, digest);
443
444 /* Convert the calculated 16 octet digest into a 32 byte hex string */
445 for(i = 0; i < MD5_DIGEST_LEN; i++)
446 snprintf(&secret[2 * i], 3, "%02x", digest[i]);
447
448 result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
449
450 if(!result)
451 state(conn, POP3_APOP);
452
453 return result;
454}
455#endif
456
457/***********************************************************************
458 *
459 * pop3_perform_auth()
460 *
461 * Sends an AUTH command allowing the client to login with the given SASL
462 * authentication mechanism.
463 */
464static CURLcode pop3_perform_auth(struct connectdata *conn,
465 const char *mech,
466 const char *initresp)
467{
468 CURLcode result = CURLE_OK;
469 struct pop3_conn *pop3c = &conn->proto.pop3c;
470
471 if(initresp) { /* AUTH <mech> ...<crlf> */
472 /* Send the AUTH command with the initial response */
473 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
474 }
475 else {
476 /* Send the AUTH command */
477 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
478 }
479
480 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100481}
482
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700483/***********************************************************************
484 *
485 * pop3_continue_auth()
486 *
487 * Sends SASL continuation data or cancellation.
488 */
489static CURLcode pop3_continue_auth(struct connectdata *conn,
490 const char *resp)
491{
492 struct pop3_conn *pop3c = &conn->proto.pop3c;
493
494 return Curl_pp_sendf(&pop3c->pp, "%s", resp);
495}
496
497/***********************************************************************
498 *
499 * pop3_perform_authentication()
500 *
501 * Initiates the authentication sequence, with the appropriate SASL
502 * authentication mechanism, falling back to APOP and clear text should a
503 * common mechanism not be available between the client and server.
504 */
505static CURLcode pop3_perform_authentication(struct connectdata *conn)
506{
507 CURLcode result = CURLE_OK;
508 struct pop3_conn *pop3c = &conn->proto.pop3c;
509 saslprogress progress = SASL_IDLE;
510
511 /* Check we have enough data to authenticate with and end the
512 connect phase if we don't */
513 if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) {
514 state(conn, POP3_STOP);
515 return result;
516 }
517
518 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
519 /* Calculate the SASL login details */
520 result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress);
521
522 if(!result)
523 if(progress == SASL_INPROGRESS)
524 state(conn, POP3_AUTH);
525 }
526
527 if(!result && progress == SASL_IDLE) {
528#ifndef CURL_DISABLE_CRYPTO_AUTH
529 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
530 /* Perform APOP authentication */
531 result = pop3_perform_apop(conn);
532 else
533#endif
534 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
535 /* Perform clear text authentication */
536 result = pop3_perform_user(conn);
537 else {
538 /* Other mechanisms not supported */
539 infof(conn->data, "No known authentication mechanisms supported!\n");
540 result = CURLE_LOGIN_DENIED;
541 }
542 }
543
544 return result;
545}
546
547/***********************************************************************
548 *
549 * pop3_perform_command()
550 *
551 * Sends a POP3 based command.
552 */
553static CURLcode pop3_perform_command(struct connectdata *conn)
554{
555 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700556 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700557 struct POP3 *pop3 = data->req.protop;
558 const char *command = NULL;
559
560 /* Calculate the default command */
561 if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
562 command = "LIST";
563
564 if(pop3->id[0] != '\0')
565 /* Message specific LIST so skip the BODY transfer */
566 pop3->transfer = FTPTRANSFER_INFO;
567 }
568 else
569 command = "RETR";
570
571 /* Send the command */
572 if(pop3->id[0] != '\0')
573 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
574 (pop3->custom && pop3->custom[0] != '\0' ?
575 pop3->custom : command), pop3->id);
576 else
577 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s",
578 (pop3->custom && pop3->custom[0] != '\0' ?
579 pop3->custom : command));
580
581 if(!result)
582 state(conn, POP3_COMMAND);
583
584 return result;
585}
586
587/***********************************************************************
588 *
589 * pop3_perform_quit()
590 *
591 * Performs the quit action prior to sclose() be called.
592 */
593static CURLcode pop3_perform_quit(struct connectdata *conn)
594{
595 CURLcode result = CURLE_OK;
596
597 /* Send the QUIT command */
598 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT");
599
600 if(!result)
601 state(conn, POP3_QUIT);
602
603 return result;
604}
605
606/* For the initial server greeting */
607static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
608 int pop3code,
609 pop3state instate)
610{
611 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700612 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700613 struct pop3_conn *pop3c = &conn->proto.pop3c;
614 const char *line = data->state.buffer;
615 size_t len = strlen(line);
616 size_t i;
617
618 (void)instate; /* no use for this yet */
619
620 if(pop3code != '+') {
621 failf(data, "Got unexpected pop3-server response");
Elliott Hughescee03382017-06-23 12:17:18 -0700622 result = CURLE_WEIRD_SERVER_REPLY;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700623 }
624 else {
625 /* Does the server support APOP authentication? */
626 if(len >= 4 && line[len - 2] == '>') {
627 /* Look for the APOP timestamp */
628 for(i = 3; i < len - 2; ++i) {
629 if(line[i] == '<') {
630 /* Calculate the length of the timestamp */
631 size_t timestamplen = len - 1 - i;
632 if(!timestamplen)
633 break;
634
635 /* Allocate some memory for the timestamp */
636 pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
637
638 if(!pop3c->apoptimestamp)
639 break;
640
641 /* Copy the timestamp */
642 memcpy(pop3c->apoptimestamp, line + i, timestamplen);
643 pop3c->apoptimestamp[timestamplen] = '\0';
644
645 /* Store the APOP capability */
646 pop3c->authtypes |= POP3_TYPE_APOP;
647 break;
648 }
649 }
650 }
651
652 result = pop3_perform_capa(conn);
653 }
654
655 return result;
656}
657
658/* For CAPA responses */
659static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
660 pop3state instate)
661{
662 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700663 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700664 struct pop3_conn *pop3c = &conn->proto.pop3c;
665 const char *line = data->state.buffer;
666 size_t len = strlen(line);
667 size_t wordlen;
668
669 (void)instate; /* no use for this yet */
670
Alex Deymod15eaac2016-06-28 14:49:26 -0700671 /* Do we have a untagged continuation response? */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700672 if(pop3code == '*') {
673 /* Does the server support the STLS capability? */
674 if(len >= 4 && !memcmp(line, "STLS", 4))
675 pop3c->tls_supported = TRUE;
676
677 /* Does the server support clear text authentication? */
678 else if(len >= 4 && !memcmp(line, "USER", 4))
679 pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
680
681 /* Does the server support SASL based authentication? */
682 else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
683 pop3c->authtypes |= POP3_TYPE_SASL;
684
685 /* Advance past the SASL keyword */
686 line += 5;
687 len -= 5;
688
689 /* Loop through the data line */
690 for(;;) {
691 size_t llen;
692 unsigned int mechbit;
693
694 while(len &&
695 (*line == ' ' || *line == '\t' ||
696 *line == '\r' || *line == '\n')) {
697
698 line++;
699 len--;
700 }
701
702 if(!len)
703 break;
704
705 /* Extract the word */
706 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
707 line[wordlen] != '\t' && line[wordlen] != '\r' &&
708 line[wordlen] != '\n';)
709 wordlen++;
710
711 /* Test the word for a matching authentication mechanism */
Alex Deymod15eaac2016-06-28 14:49:26 -0700712 mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
713 if(mechbit && llen == wordlen)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700714 pop3c->sasl.authmechs |= mechbit;
715
716 line += wordlen;
717 len -= wordlen;
718 }
719 }
720 }
721 else if(pop3code == '+') {
722 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
723 /* We don't have a SSL/TLS connection yet, but SSL is requested */
724 if(pop3c->tls_supported)
725 /* Switch to TLS connection now */
726 result = pop3_perform_starttls(conn);
727 else if(data->set.use_ssl == CURLUSESSL_TRY)
728 /* Fallback and carry on with authentication */
729 result = pop3_perform_authentication(conn);
730 else {
731 failf(data, "STLS not supported.");
732 result = CURLE_USE_SSL_FAILED;
733 }
734 }
735 else
736 result = pop3_perform_authentication(conn);
737 }
738 else {
739 /* Clear text is supported when CAPA isn't recognised */
740 pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
741
742 result = pop3_perform_authentication(conn);
743 }
744
745 return result;
746}
747
748/* For STARTTLS responses */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100749static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
750 int pop3code,
751 pop3state instate)
752{
753 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700754 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700755
Kristian Monsen5ab50182010-05-14 18:53:44 +0100756 (void)instate; /* no use for this yet */
757
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700758 if(pop3code != '+') {
759 if(data->set.use_ssl != CURLUSESSL_TRY) {
Elliott Hughes82be86d2017-09-20 17:00:17 -0700760 failf(data, "STARTTLS denied");
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700761 result = CURLE_USE_SSL_FAILED;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100762 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700763 else
764 result = pop3_perform_authentication(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100765 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700766 else
767 result = pop3_perform_upgrade_tls(conn);
768
Kristian Monsen5ab50182010-05-14 18:53:44 +0100769 return result;
770}
771
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700772/* For SASL authentication responses */
773static CURLcode pop3_state_auth_resp(struct connectdata *conn,
Kristian Monsen5ab50182010-05-14 18:53:44 +0100774 int pop3code,
775 pop3state instate)
776{
777 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700778 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700779 struct pop3_conn *pop3c = &conn->proto.pop3c;
780 saslprogress progress;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100781
782 (void)instate; /* no use for this yet */
783
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700784 result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress);
785 if(!result)
786 switch(progress) {
787 case SASL_DONE:
788 state(conn, POP3_STOP); /* Authenticated */
789 break;
790 case SASL_IDLE: /* No mechanism left after cancellation */
791#ifndef CURL_DISABLE_CRYPTO_AUTH
792 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
793 /* Perform APOP authentication */
794 result = pop3_perform_apop(conn);
795 else
796#endif
797 if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
798 /* Perform clear text authentication */
799 result = pop3_perform_user(conn);
800 else {
801 failf(data, "Authentication cancelled");
802 result = CURLE_LOGIN_DENIED;
803 }
804 break;
805 default:
806 break;
807 }
808
809 return result;
810}
811
812#ifndef CURL_DISABLE_CRYPTO_AUTH
813/* For APOP responses */
814static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
815 pop3state instate)
816{
817 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700818 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700819
820 (void)instate; /* no use for this yet */
821
822 if(pop3code != '+') {
823 failf(data, "Authentication failed: %d", pop3code);
824 result = CURLE_LOGIN_DENIED;
825 }
826 else
827 /* End of connect phase */
828 state(conn, POP3_STOP);
829
830 return result;
831}
832#endif
833
834/* For USER responses */
835static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
836 pop3state instate)
837{
838 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700839 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700840
841 (void)instate; /* no use for this yet */
842
843 if(pop3code != '+') {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100844 failf(data, "Access denied. %c", pop3code);
845 result = CURLE_LOGIN_DENIED;
846 }
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700847 else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700848 /* Send the PASS command */
Lucas Eckels9bd90e62012-08-06 15:07:02 -0700849 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700850 conn->passwd ? conn->passwd : "");
851 if(!result)
852 state(conn, POP3_PASS);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100853
Kristian Monsen5ab50182010-05-14 18:53:44 +0100854 return result;
855}
856
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700857/* For PASS responses */
858static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
Kristian Monsen5ab50182010-05-14 18:53:44 +0100859 pop3state instate)
860{
861 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700862 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700863
Kristian Monsen5ab50182010-05-14 18:53:44 +0100864 (void)instate; /* no use for this yet */
865
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700866 if(pop3code != '+') {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100867 failf(data, "Access denied. %c", pop3code);
868 result = CURLE_LOGIN_DENIED;
869 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700870 else
871 /* End of connect phase */
872 state(conn, POP3_STOP);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100873
Kristian Monsen5ab50182010-05-14 18:53:44 +0100874 return result;
875}
876
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700877/* For command responses */
878static CURLcode pop3_state_command_resp(struct connectdata *conn,
879 int pop3code,
880 pop3state instate)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100881{
882 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700883 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700884 struct POP3 *pop3 = data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100885 struct pop3_conn *pop3c = &conn->proto.pop3c;
886 struct pingpong *pp = &pop3c->pp;
887
888 (void)instate; /* no use for this yet */
889
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700890 if(pop3code != '+') {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100891 state(conn, POP3_STOP);
892 return CURLE_RECV_ERROR;
893 }
894
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700895 /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
896 EOB string so count this is two matching bytes. This is necessary to make
897 the code detect the EOB if the only data than comes now is %2e CR LF like
898 when there is no body to return. */
899 pop3c->eob = 2;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100900
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700901 /* But since this initial CR LF pair is not part of the actual body, we set
902 the strip counter here so that these bytes won't be delivered. */
903 pop3c->strip = 2;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100904
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700905 if(pop3->transfer == FTPTRANSFER_BODY) {
906 /* POP3 download */
907 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100908
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700909 if(pp->cache) {
910 /* The header "cache" contains a bunch of data that is actually body
911 content so send it as such. Note that there may even be additional
912 "headers" after the body */
913
914 if(!data->set.opt_no_body) {
915 result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
916 if(result)
917 return result;
918 }
919
920 /* Free the cache */
921 Curl_safefree(pp->cache);
922
923 /* Reset the cache size */
924 pp->cache_size = 0;
925 }
Kristian Monsen5ab50182010-05-14 18:53:44 +0100926 }
927
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700928 /* End of DO phase */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100929 state(conn, POP3_STOP);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100930
Kristian Monsen5ab50182010-05-14 18:53:44 +0100931 return result;
932}
933
934static CURLcode pop3_statemach_act(struct connectdata *conn)
935{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700936 CURLcode result = CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100937 curl_socket_t sock = conn->sock[FIRSTSOCKET];
Kristian Monsen5ab50182010-05-14 18:53:44 +0100938 int pop3code;
939 struct pop3_conn *pop3c = &conn->proto.pop3c;
940 struct pingpong *pp = &pop3c->pp;
941 size_t nread = 0;
942
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700943 /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
944 if(pop3c->state == POP3_UPGRADETLS)
945 return pop3_perform_upgrade_tls(conn);
946
947 /* Flush any data that needs to be sent */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100948 if(pp->sendleft)
949 return Curl_pp_flushsend(pp);
950
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700951 do {
952 /* Read the response from the server */
953 result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
954 if(result)
955 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100956
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700957 if(!pop3code)
958 break;
959
960 /* We have now received a full POP3 server response */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100961 switch(pop3c->state) {
962 case POP3_SERVERGREET:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700963 result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100964 break;
965
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700966 case POP3_CAPA:
967 result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
968 break;
969
970 case POP3_STARTTLS:
971 result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
972 break;
973
974 case POP3_AUTH:
975 result = pop3_state_auth_resp(conn, pop3code, pop3c->state);
976 break;
977
978#ifndef CURL_DISABLE_CRYPTO_AUTH
979 case POP3_APOP:
980 result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
981 break;
982#endif
983
Kristian Monsen5ab50182010-05-14 18:53:44 +0100984 case POP3_USER:
985 result = pop3_state_user_resp(conn, pop3code, pop3c->state);
986 break;
987
988 case POP3_PASS:
989 result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
990 break;
991
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700992 case POP3_COMMAND:
993 result = pop3_state_command_resp(conn, pop3code, pop3c->state);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100994 break;
995
996 case POP3_QUIT:
997 /* fallthrough, just stop! */
998 default:
999 /* internal error */
1000 state(conn, POP3_STOP);
1001 break;
1002 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001003 } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
1004
Kristian Monsen5ab50182010-05-14 18:53:44 +01001005 return result;
1006}
1007
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001008/* Called repeatedly until done from multi.c */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001009static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
1010{
Kristian Monsen5ab50182010-05-14 18:53:44 +01001011 CURLcode result = CURLE_OK;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001012 struct pop3_conn *pop3c = &conn->proto.pop3c;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001013
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001014 if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
1015 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
1016 if(result || !pop3c->ssldone)
1017 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001018 }
1019
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001020 result = Curl_pp_statemach(&pop3c->pp, FALSE);
1021 *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
1022
Kristian Monsen5ab50182010-05-14 18:53:44 +01001023 return result;
1024}
1025
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001026static CURLcode pop3_block_statemach(struct connectdata *conn)
1027{
1028 CURLcode result = CURLE_OK;
1029 struct pop3_conn *pop3c = &conn->proto.pop3c;
1030
1031 while(pop3c->state != POP3_STOP && !result)
1032 result = Curl_pp_statemach(&pop3c->pp, TRUE);
1033
1034 return result;
1035}
1036
Alex Deymoe3149cc2016-10-05 11:18:42 -07001037/* Allocate and initialize the POP3 struct for the current Curl_easy if
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001038 required */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001039static CURLcode pop3_init(struct connectdata *conn)
1040{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001041 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001042 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001043 struct POP3 *pop3;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001044
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001045 pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
1046 if(!pop3)
1047 result = CURLE_OUT_OF_MEMORY;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001048
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001049 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001050}
1051
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001052/* For the POP3 "protocol connect" and "doing" phases only */
1053static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
1054 int numsocks)
1055{
1056 return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
1057}
1058
1059/***********************************************************************
1060 *
1061 * pop3_connect()
1062 *
1063 * This function should do everything that is to be considered a part of the
1064 * connection phase.
Kristian Monsen5ab50182010-05-14 18:53:44 +01001065 *
1066 * The variable 'done' points to will be TRUE if the protocol-layer connect
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001067 * phase is done when this function returns, or FALSE if not.
Kristian Monsen5ab50182010-05-14 18:53:44 +01001068 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001069static CURLcode pop3_connect(struct connectdata *conn, bool *done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001070{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001071 CURLcode result = CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001072 struct pop3_conn *pop3c = &conn->proto.pop3c;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001073 struct pingpong *pp = &pop3c->pp;
1074
1075 *done = FALSE; /* default to not done yet */
1076
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001077 /* We always support persistent connections in POP3 */
1078 connkeep(conn, "POP3 default");
Kristian Monsen5ab50182010-05-14 18:53:44 +01001079
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001080 /* Set the default response time-out */
1081 pp->response_time = RESP_TIMEOUT;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001082 pp->statemach_act = pop3_statemach_act;
1083 pp->endofresp = pop3_endofresp;
1084 pp->conn = conn;
1085
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001086 /* Set the default preferred authentication type and mechanism */
1087 pop3c->preftype = POP3_TYPE_ANY;
1088 Curl_sasl_init(&pop3c->sasl, &saslpop3);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001089
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001090 /* Initialise the pingpong layer */
1091 Curl_pp_init(pp);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001092
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001093 /* Parse the URL options */
1094 result = pop3_parse_url_options(conn);
1095 if(result)
1096 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001097
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001098 /* Start off waiting for the server greeting response */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001099 state(conn, POP3_SERVERGREET);
1100
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001101 result = pop3_multi_statemach(conn, done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001102
1103 return result;
1104}
1105
1106/***********************************************************************
1107 *
1108 * pop3_done()
1109 *
1110 * The DONE function. This does what needs to be done after a single DO has
1111 * performed.
1112 *
1113 * Input argument is already checked for validity.
1114 */
1115static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
1116 bool premature)
1117{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001118 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001119 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001120 struct POP3 *pop3 = data->req.protop;
1121
Kristian Monsen5ab50182010-05-14 18:53:44 +01001122 (void)premature;
1123
1124 if(!pop3)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001125 return CURLE_OK;
1126
1127 if(status) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001128 connclose(conn, "POP3 done with bad status");
1129 result = status; /* use the already set error code */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001130 }
1131
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001132 /* Cleanup our per-request based variables */
1133 Curl_safefree(pop3->id);
1134 Curl_safefree(pop3->custom);
1135
1136 /* Clear the transfer mode for the next request */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001137 pop3->transfer = FTPTRANSFER_BODY;
1138
1139 return result;
1140}
1141
1142/***********************************************************************
1143 *
1144 * pop3_perform()
1145 *
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001146 * This is the actual DO function for POP3. Get a message/listing according to
Kristian Monsen5ab50182010-05-14 18:53:44 +01001147 * the options previously setup.
1148 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001149static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
1150 bool *dophase_done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001151{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001152 /* This is POP3 and no proxy */
1153 CURLcode result = CURLE_OK;
1154 struct POP3 *pop3 = conn->data->req.protop;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001155
1156 DEBUGF(infof(conn->data, "DO phase starts\n"));
1157
1158 if(conn->data->set.opt_no_body) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001159 /* Requested no body means no transfer */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001160 pop3->transfer = FTPTRANSFER_INFO;
1161 }
1162
1163 *dophase_done = FALSE; /* not done yet */
1164
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001165 /* Start the first command in the DO phase */
1166 result = pop3_perform_command(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001167 if(result)
1168 return result;
1169
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001170 /* Run the state-machine */
1171 result = pop3_multi_statemach(conn, dophase_done);
1172
1173 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
Kristian Monsen5ab50182010-05-14 18:53:44 +01001174
1175 if(*dophase_done)
1176 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1177
1178 return result;
1179}
1180
1181/***********************************************************************
1182 *
1183 * pop3_do()
1184 *
1185 * This function is registered as 'curl_do' function. It decodes the path
1186 * parts etc as a wrapper to the actual DO function (pop3_perform).
1187 *
1188 * The input argument is already checked for validity.
1189 */
1190static CURLcode pop3_do(struct connectdata *conn, bool *done)
1191{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001192 CURLcode result = CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001193
1194 *done = FALSE; /* default to false */
1195
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001196 /* Parse the URL path */
1197 result = pop3_parse_url_path(conn);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001198 if(result)
1199 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001200
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001201 /* Parse the custom request */
1202 result = pop3_parse_custom_request(conn);
1203 if(result)
1204 return result;
1205
1206 result = pop3_regular_transfer(conn, done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001207
1208 return result;
1209}
1210
1211/***********************************************************************
1212 *
1213 * pop3_disconnect()
1214 *
1215 * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
1216 * resources. BLOCKING.
1217 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001218static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001219{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001220 struct pop3_conn *pop3c = &conn->proto.pop3c;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001221
1222 /* We cannot send quit unconditionally. If this connection is stale or
1223 bad in any way, sending quit and waiting around here will make the
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001224 disconnect wait in vain and cause more problems than we need to. */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001225
1226 /* The POP3 session may or may not have been allocated/setup at this
1227 point! */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001228 if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
1229 if(!pop3_perform_quit(conn))
1230 (void)pop3_block_statemach(conn); /* ignore errors on QUIT */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001231
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001232 /* Disconnect from the server */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001233 Curl_pp_disconnect(&pop3c->pp);
1234
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001235 /* Cleanup the SASL module */
1236 Curl_sasl_cleanup(conn, pop3c->sasl.authused);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001237
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001238 /* Cleanup our connection based variables */
1239 Curl_safefree(pop3c->apoptimestamp);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001240
1241 return CURLE_OK;
1242}
1243
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001244/* Call this when the DO phase has completed */
1245static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001246{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001247 (void)conn;
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001248 (void)connected;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001249
Lucas Eckels9bd90e62012-08-06 15:07:02 -07001250 return CURLE_OK;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001251}
1252
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001253/* Called from multi.c while DOing */
1254static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001255{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001256 CURLcode result = pop3_multi_statemach(conn, dophase_done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001257
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001258 if(result)
1259 DEBUGF(infof(conn->data, "DO phase failed\n"));
1260 else if(*dophase_done) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001261 result = pop3_dophase_done(conn, FALSE /* not connected */);
1262
1263 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1264 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001265
Kristian Monsen5ab50182010-05-14 18:53:44 +01001266 return result;
1267}
1268
1269/***********************************************************************
1270 *
1271 * pop3_regular_transfer()
1272 *
1273 * The input argument is already checked for validity.
1274 *
1275 * Performs all commands done before a regular transfer between a local and a
1276 * remote host.
Kristian Monsen5ab50182010-05-14 18:53:44 +01001277 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001278static CURLcode pop3_regular_transfer(struct connectdata *conn,
1279 bool *dophase_done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001280{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001281 CURLcode result = CURLE_OK;
1282 bool connected = FALSE;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001283 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001284
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001285 /* Make sure size is unknown at this point */
1286 data->req.size = -1;
1287
1288 /* Set the progress data */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001289 Curl_pgrsSetUploadCounter(data, 0);
1290 Curl_pgrsSetDownloadCounter(data, 0);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001291 Curl_pgrsSetUploadSize(data, -1);
1292 Curl_pgrsSetDownloadSize(data, -1);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001293
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001294 /* Carry out the perform */
1295 result = pop3_perform(conn, &connected, dophase_done);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001296
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001297 /* Perform post DO phase operations if necessary */
1298 if(!result && *dophase_done)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001299 result = pop3_dophase_done(conn, connected);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001300
1301 return result;
1302}
1303
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001304static CURLcode pop3_setup_connection(struct connectdata *conn)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001305{
Alex Deymoe3149cc2016-10-05 11:18:42 -07001306 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001307
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001308 /* Initialise the POP3 layer */
1309 CURLcode result = pop3_init(conn);
1310 if(result)
1311 return result;
1312
Alex Deymod15eaac2016-06-28 14:49:26 -07001313 /* Clear the TLS upgraded flag */
1314 conn->tls_upgraded = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001315 data->state.path++; /* don't include the initial slash */
1316
1317 return CURLE_OK;
1318}
1319
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001320/***********************************************************************
1321 *
1322 * pop3_parse_url_options()
1323 *
1324 * Parse the URL login options.
1325 */
1326static CURLcode pop3_parse_url_options(struct connectdata *conn)
1327{
1328 CURLcode result = CURLE_OK;
1329 struct pop3_conn *pop3c = &conn->proto.pop3c;
1330 const char *ptr = conn->options;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001331
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001332 pop3c->sasl.resetprefs = TRUE;
1333
1334 while(!result && ptr && *ptr) {
1335 const char *key = ptr;
1336 const char *value;
1337
1338 while(*ptr && *ptr != '=')
1339 ptr++;
1340
1341 value = ptr + 1;
1342
1343 while(*ptr && *ptr != ';')
1344 ptr++;
1345
Elliott Hughescee03382017-06-23 12:17:18 -07001346 if(strncasecompare(key, "AUTH=", 5)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001347 result = Curl_sasl_parse_url_auth_option(&pop3c->sasl,
1348 value, ptr - value);
1349
Elliott Hughescee03382017-06-23 12:17:18 -07001350 if(result && strncasecompare(value, "+APOP", ptr - value)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001351 pop3c->preftype = POP3_TYPE_APOP;
1352 pop3c->sasl.prefmech = SASL_AUTH_NONE;
1353 result = CURLE_OK;
1354 }
1355 }
1356 else
1357 result = CURLE_URL_MALFORMAT;
1358
1359 if(*ptr == ';')
1360 ptr++;
1361 }
1362
1363 if(pop3c->preftype != POP3_TYPE_APOP)
1364 switch(pop3c->sasl.prefmech) {
1365 case SASL_AUTH_NONE:
1366 pop3c->preftype = POP3_TYPE_NONE;
1367 break;
1368 case SASL_AUTH_DEFAULT:
1369 pop3c->preftype = POP3_TYPE_ANY;
1370 break;
1371 default:
1372 pop3c->preftype = POP3_TYPE_SASL;
1373 break;
1374 }
1375
1376 return result;
1377}
1378
1379/***********************************************************************
1380 *
1381 * pop3_parse_url_path()
1382 *
1383 * Parse the URL path into separate path components.
1384 */
1385static CURLcode pop3_parse_url_path(struct connectdata *conn)
1386{
1387 /* The POP3 struct is already initialised in pop3_connect() */
Alex Deymoe3149cc2016-10-05 11:18:42 -07001388 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001389 struct POP3 *pop3 = data->req.protop;
1390 const char *path = data->state.path;
1391
1392 /* URL decode the path for the message ID */
1393 return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
1394}
1395
1396/***********************************************************************
1397 *
1398 * pop3_parse_custom_request()
1399 *
1400 * Parse the custom request.
1401 */
1402static CURLcode pop3_parse_custom_request(struct connectdata *conn)
1403{
1404 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001405 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001406 struct POP3 *pop3 = data->req.protop;
1407 const char *custom = data->set.str[STRING_CUSTOMREQUEST];
1408
1409 /* URL decode the custom request */
1410 if(custom)
1411 result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
1412
1413 return result;
1414}
1415
1416/***********************************************************************
1417 *
1418 * Curl_pop3_write()
1419 *
Kristian Monsen5ab50182010-05-14 18:53:44 +01001420 * This function scans the body after the end-of-body and writes everything
1421 * until the end is found.
1422 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001423CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001424{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001425 /* This code could be made into a special function in the handler struct */
1426 CURLcode result = CURLE_OK;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001427 struct Curl_easy *data = conn->data;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001428 struct SingleRequest *k = &data->req;
1429
Kristian Monsen5ab50182010-05-14 18:53:44 +01001430 struct pop3_conn *pop3c = &conn->proto.pop3c;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001431 bool strip_dot = FALSE;
1432 size_t last = 0;
1433 size_t i;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001434
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001435 /* Search through the buffer looking for the end-of-body marker which is
1436 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
1437 the eob so the server will have prefixed it with an extra dot which we
1438 need to strip out. Additionally the marker could of course be spread out
1439 over 5 different data chunks. */
1440 for(i = 0; i < nread; i++) {
1441 size_t prev = pop3c->eob;
1442
1443 switch(str[i]) {
1444 case 0x0d:
1445 if(pop3c->eob == 0) {
1446 pop3c->eob++;
1447
1448 if(i) {
1449 /* Write out the body part that didn't match */
1450 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
1451 i - last);
1452
1453 if(result)
1454 return result;
1455
1456 last = i;
1457 }
1458 }
1459 else if(pop3c->eob == 3)
1460 pop3c->eob++;
1461 else
1462 /* If the character match wasn't at position 0 or 3 then restart the
1463 pattern matching */
1464 pop3c->eob = 1;
1465 break;
1466
1467 case 0x0a:
1468 if(pop3c->eob == 1 || pop3c->eob == 4)
1469 pop3c->eob++;
1470 else
1471 /* If the character match wasn't at position 1 or 4 then start the
1472 search again */
1473 pop3c->eob = 0;
1474 break;
1475
1476 case 0x2e:
1477 if(pop3c->eob == 2)
1478 pop3c->eob++;
1479 else if(pop3c->eob == 3) {
1480 /* We have an extra dot after the CRLF which we need to strip off */
1481 strip_dot = TRUE;
1482 pop3c->eob = 0;
1483 }
1484 else
1485 /* If the character match wasn't at position 2 then start the search
1486 again */
1487 pop3c->eob = 0;
1488 break;
1489
1490 default:
Kristian Monsen5ab50182010-05-14 18:53:44 +01001491 pop3c->eob = 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001492 break;
1493 }
1494
1495 /* Did we have a partial match which has subsequently failed? */
1496 if(prev && prev >= pop3c->eob) {
1497 /* Strip can only be non-zero for the very first mismatch after CRLF
1498 and then both prev and strip are equal and nothing will be output
1499 below */
1500 while(prev && pop3c->strip) {
1501 prev--;
1502 pop3c->strip--;
1503 }
1504
1505 if(prev) {
1506 /* If the partial match was the CRLF and dot then only write the CRLF
1507 as the server would have inserted the dot */
Elliott Hughescee03382017-06-23 12:17:18 -07001508 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001509 strip_dot ? prev - 1 : prev);
1510
1511 if(result)
1512 return result;
1513
1514 last = i;
1515 strip_dot = FALSE;
1516 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001517 }
1518 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001519
1520 if(pop3c->eob == POP3_EOB_LEN) {
1521 /* We have a full match so the transfer is done, however we must transfer
1522 the CRLF at the start of the EOB as this is considered to be part of the
1523 message as per RFC-1939, sect. 3 */
1524 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
1525
1526 k->keepon &= ~KEEP_RECV;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001527 pop3c->eob = 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001528
1529 return result;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001530 }
1531
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001532 if(pop3c->eob)
1533 /* While EOB is matching nothing should be output */
1534 return CURLE_OK;
1535
1536 if(nread - last) {
1537 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
1538 nread - last);
1539 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001540
1541 return result;
1542}
1543
1544#endif /* CURL_DISABLE_POP3 */