source: azure_iot_hub/trunk/curl-7.57.0/lib/pop3.c@ 388

Last change on this file since 388 was 388, checked in by coas-nagasima, 5 years ago

Azure IoT Hub Device C SDK を使ったサンプルの追加

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