VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/pop3.c@ 98704

最後變更 在這個檔案從98704是 98326,由 vboxsync 提交於 2 年 前

curl-7.87.0: Applied and adjusted our curl changes to 7.83.1. bugref:10356

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette