1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
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 http://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
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 * RFC5034 POP3 SASL Authentication Mechanism
31 * RFC6749 OAuth 2.0 Authorization Framework
32 * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
34 ***************************************************************************/
36 #include "curl_setup.h"
38 #ifndef CURL_DISABLE_POP3
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
47 #include <sys/utsname.h>
57 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
59 #define in_addr_t unsigned long
62 #include <curl/curl.h>
70 #include "http.h" /* for HTTP proxy tunnel stuff */
74 #include "strtoofft.h"
83 #include "curl_sasl.h"
87 #define _MPRINTF_REPLACE /* use our functions only */
88 #include <curl/mprintf.h>
90 #include "curl_memory.h"
91 /* The last #include file should be: */
94 /* Local API functions */
95 static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
96 static CURLcode pop3_do(struct connectdata *conn, bool *done);
97 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
99 static CURLcode pop3_connect(struct connectdata *conn, bool *done);
100 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
101 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
102 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
104 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
105 static CURLcode pop3_setup_connection(struct connectdata *conn);
106 static CURLcode pop3_parse_url_options(struct connectdata *conn);
107 static CURLcode pop3_parse_url_path(struct connectdata *conn);
108 static CURLcode pop3_parse_custom_request(struct connectdata *conn);
111 * POP3 protocol handler.
114 const struct Curl_handler Curl_handler_pop3 = {
116 pop3_setup_connection, /* setup_connection */
118 pop3_done, /* done */
119 ZERO_NULL, /* do_more */
120 pop3_connect, /* connect_it */
121 pop3_multi_statemach, /* connecting */
122 pop3_doing, /* doing */
123 pop3_getsock, /* proto_getsock */
124 pop3_getsock, /* doing_getsock */
125 ZERO_NULL, /* domore_getsock */
126 ZERO_NULL, /* perform_getsock */
127 pop3_disconnect, /* disconnect */
128 ZERO_NULL, /* readwrite */
129 PORT_POP3, /* defport */
130 CURLPROTO_POP3, /* protocol */
131 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
136 * POP3S protocol handler.
139 const struct Curl_handler Curl_handler_pop3s = {
140 "POP3S", /* scheme */
141 pop3_setup_connection, /* setup_connection */
143 pop3_done, /* done */
144 ZERO_NULL, /* do_more */
145 pop3_connect, /* connect_it */
146 pop3_multi_statemach, /* connecting */
147 pop3_doing, /* doing */
148 pop3_getsock, /* proto_getsock */
149 pop3_getsock, /* doing_getsock */
150 ZERO_NULL, /* domore_getsock */
151 ZERO_NULL, /* perform_getsock */
152 pop3_disconnect, /* disconnect */
153 ZERO_NULL, /* readwrite */
154 PORT_POP3S, /* defport */
155 CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */
156 PROTOPT_CLOSEACTION | PROTOPT_SSL
157 | PROTOPT_NOURLQUERY /* flags */
161 #ifndef CURL_DISABLE_HTTP
163 * HTTP-proxyed POP3 protocol handler.
166 static const struct Curl_handler Curl_handler_pop3_proxy = {
168 Curl_http_setup_conn, /* setup_connection */
169 Curl_http, /* do_it */
170 Curl_http_done, /* done */
171 ZERO_NULL, /* do_more */
172 ZERO_NULL, /* connect_it */
173 ZERO_NULL, /* connecting */
174 ZERO_NULL, /* doing */
175 ZERO_NULL, /* proto_getsock */
176 ZERO_NULL, /* doing_getsock */
177 ZERO_NULL, /* domore_getsock */
178 ZERO_NULL, /* perform_getsock */
179 ZERO_NULL, /* disconnect */
180 ZERO_NULL, /* readwrite */
181 PORT_POP3, /* defport */
182 CURLPROTO_HTTP, /* protocol */
183 PROTOPT_NONE /* flags */
188 * HTTP-proxyed POP3S protocol handler.
191 static const struct Curl_handler Curl_handler_pop3s_proxy = {
192 "POP3S", /* scheme */
193 Curl_http_setup_conn, /* setup_connection */
194 Curl_http, /* do_it */
195 Curl_http_done, /* done */
196 ZERO_NULL, /* do_more */
197 ZERO_NULL, /* connect_it */
198 ZERO_NULL, /* connecting */
199 ZERO_NULL, /* doing */
200 ZERO_NULL, /* proto_getsock */
201 ZERO_NULL, /* doing_getsock */
202 ZERO_NULL, /* domore_getsock */
203 ZERO_NULL, /* perform_getsock */
204 ZERO_NULL, /* disconnect */
205 ZERO_NULL, /* readwrite */
206 PORT_POP3S, /* defport */
207 CURLPROTO_HTTP, /* protocol */
208 PROTOPT_NONE /* flags */
214 static void pop3_to_pop3s(struct connectdata *conn)
216 conn->handler = &Curl_handler_pop3s;
219 #define pop3_to_pop3s(x) Curl_nop_stmt
222 /***********************************************************************
226 * Checks for an ending POP3 status code at the start of the given string, but
227 * also detects the APOP timestamp from the server greeting and various
228 * capabilities from the CAPA response including the supported authentication
229 * types and allowed SASL mechanisms.
231 static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
234 struct pop3_conn *pop3c = &conn->proto.pop3c;
238 /* Do we have an error response? */
239 if(len >= 4 && !memcmp("-ERR", line, 4)) {
245 /* Are we processing servergreet responses? */
246 if(pop3c->state == POP3_SERVERGREET) {
247 /* Look for the APOP timestamp */
248 if(len >= 3 && line[len - 3] == '>') {
249 for(i = 0; i < len - 3; ++i) {
251 /* Calculate the length of the timestamp */
252 size_t timestamplen = len - 2 - i;
254 /* Allocate some memory for the timestamp */
255 pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
257 if(!pop3c->apoptimestamp)
260 /* Copy the timestamp */
261 memcpy(pop3c->apoptimestamp, line + i, timestamplen);
262 pop3c->apoptimestamp[timestamplen] = '\0';
268 /* Are we processing CAPA command responses? */
269 else if(pop3c->state == POP3_CAPA) {
270 /* Do we have the terminating line? */
271 if(len >= 1 && !memcmp(line, ".", 1)) {
277 /* Does the server support the STLS capability? */
278 if(len >= 4 && !memcmp(line, "STLS", 4))
279 pop3c->tls_supported = TRUE;
281 /* Does the server support clear text authentication? */
282 else if(len >= 4 && !memcmp(line, "USER", 4))
283 pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
285 /* Does the server support APOP authentication? */
286 else if(len >= 4 && !memcmp(line, "APOP", 4))
287 pop3c->authtypes |= POP3_TYPE_APOP;
289 /* Does the server support SASL based authentication? */
290 else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
291 pop3c->authtypes |= POP3_TYPE_SASL;
293 /* Advance past the SASL keyword */
297 /* Loop through the data line */
300 (*line == ' ' || *line == '\t' ||
301 *line == '\r' || *line == '\n')) {
310 /* Extract the word */
311 for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
312 line[wordlen] != '\t' && line[wordlen] != '\r' &&
313 line[wordlen] != '\n';)
316 /* Test the word for a matching authentication mechanism */
317 if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
318 pop3c->authmechs |= SASL_MECH_LOGIN;
319 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
320 pop3c->authmechs |= SASL_MECH_PLAIN;
321 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
322 pop3c->authmechs |= SASL_MECH_CRAM_MD5;
323 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
324 pop3c->authmechs |= SASL_MECH_DIGEST_MD5;
325 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
326 pop3c->authmechs |= SASL_MECH_GSSAPI;
327 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
328 pop3c->authmechs |= SASL_MECH_EXTERNAL;
329 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
330 pop3c->authmechs |= SASL_MECH_NTLM;
331 else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
332 pop3c->authmechs |= SASL_MECH_XOAUTH2;
342 /* Do we have a command or continuation response? */
343 if((len >= 3 && !memcmp("+OK", line, 3)) ||
344 (len >= 1 && !memcmp("+", line, 1))) {
350 return FALSE; /* Nothing for us */
353 /***********************************************************************
357 * Gets the authentication message from the response buffer.
359 static void pop3_get_message(char *buffer, char** outptr)
362 char* message = NULL;
364 /* Find the start of the message */
365 for(message = buffer + 2; *message == ' ' || *message == '\t'; message++)
368 /* Find the end of the message */
369 for(len = strlen(message); len--;)
370 if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
371 message[len] != '\t')
374 /* Terminate the message */
382 /***********************************************************************
386 * This is the ONLY way to change POP3 state!
388 static void state(struct connectdata *conn, pop3state newstate)
390 struct pop3_conn *pop3c = &conn->proto.pop3c;
391 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
392 /* for debug purposes */
393 static const char * const names[] = {
404 "AUTH_DIGESTMD5_RESP",
406 "AUTH_NTLM_TYPE2MSG",
418 if(pop3c->state != newstate)
419 infof(conn->data, "POP3 %p state change from %s to %s\n",
420 (void *)pop3c, names[pop3c->state], names[newstate]);
423 pop3c->state = newstate;
426 /***********************************************************************
428 * pop3_perform_capa()
430 * Sends the CAPA command in order to obtain a list of server side supported
433 static CURLcode pop3_perform_capa(struct connectdata *conn)
435 CURLcode result = CURLE_OK;
436 struct pop3_conn *pop3c = &conn->proto.pop3c;
438 pop3c->authmechs = 0; /* No known authentication mechanisms yet */
439 pop3c->authused = 0; /* Clear the authentication mechanism used */
440 pop3c->tls_supported = FALSE; /* Clear the TLS capability */
442 /* Send the CAPA command */
443 result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA");
446 state(conn, POP3_CAPA);
451 /***********************************************************************
453 * pop3_perform_starttls()
455 * Sends the STLS command to start the upgrade to TLS.
457 static CURLcode pop3_perform_starttls(struct connectdata *conn)
459 CURLcode result = CURLE_OK;
461 /* Send the STLS command */
462 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS");
465 state(conn, POP3_STARTTLS);
470 /***********************************************************************
472 * pop3_perform_upgrade_tls()
474 * Performs the upgrade to TLS.
476 static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
478 CURLcode result = CURLE_OK;
479 struct pop3_conn *pop3c = &conn->proto.pop3c;
481 /* Start the SSL connection */
482 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
485 if(pop3c->state != POP3_UPGRADETLS)
486 state(conn, POP3_UPGRADETLS);
490 result = pop3_perform_capa(conn);
497 /***********************************************************************
499 * pop3_perform_user()
501 * Sends a clear text USER command to authenticate with.
503 static CURLcode pop3_perform_user(struct connectdata *conn)
505 CURLcode result = CURLE_OK;
507 /* Check we have a username and password to authenticate with and end the
508 connect phase if we don't */
509 if(!conn->bits.user_passwd) {
510 state(conn, POP3_STOP);
515 /* Send the USER command */
516 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
517 conn->user ? conn->user : "");
519 state(conn, POP3_USER);
524 #ifndef CURL_DISABLE_CRYPTO_AUTH
525 /***********************************************************************
527 * pop3_perform_apop()
529 * Sends an APOP command to authenticate with.
531 static CURLcode pop3_perform_apop(struct connectdata *conn)
533 CURLcode result = CURLE_OK;
534 struct pop3_conn *pop3c = &conn->proto.pop3c;
537 unsigned char digest[MD5_DIGEST_LEN];
538 char secret[2 * MD5_DIGEST_LEN + 1];
540 /* Check we have a username and password to authenticate with and end the
541 connect phase if we don't */
542 if(!conn->bits.user_passwd) {
543 state(conn, POP3_STOP);
548 /* Create the digest */
549 ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
551 return CURLE_OUT_OF_MEMORY;
553 Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
554 curlx_uztoui(strlen(pop3c->apoptimestamp)));
556 Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
557 curlx_uztoui(strlen(conn->passwd)));
559 /* Finalise the digest */
560 Curl_MD5_final(ctxt, digest);
562 /* Convert the calculated 16 octet digest into a 32 byte hex string */
563 for(i = 0; i < MD5_DIGEST_LEN; i++)
564 snprintf(&secret[2 * i], 3, "%02x", digest[i]);
566 result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
569 state(conn, POP3_APOP);
575 /***********************************************************************
577 * pop3_perform_authentication()
579 * Initiates the authentication sequence, with the appropriate SASL
580 * authentication mechanism, falling back to APOP and clear text should a
581 * common mechanism not be available between the client and server.
583 static CURLcode pop3_perform_authentication(struct connectdata *conn)
585 CURLcode result = CURLE_OK;
586 struct SessionHandle *data = conn->data;
587 struct pop3_conn *pop3c = &conn->proto.pop3c;
588 const char *mech = NULL;
589 char *initresp = NULL;
591 pop3state state1 = POP3_STOP;
592 pop3state state2 = POP3_STOP;
594 /* Check we have a username and password to authenticate with and end the
595 connect phase if we don't */
596 if(!conn->bits.user_passwd) {
597 state(conn, POP3_STOP);
602 /* Calculate the supported authentication mechanism, by decreasing order of
603 security, as well as the initial response where appropriate */
604 if(pop3c->authtypes & POP3_TYPE_SASL) {
605 #ifndef CURL_DISABLE_CRYPTO_AUTH
606 if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) &&
607 (pop3c->prefmech & SASL_MECH_DIGEST_MD5)) {
608 mech = SASL_MECH_STRING_DIGEST_MD5;
609 state1 = POP3_AUTH_DIGESTMD5;
610 pop3c->authused = SASL_MECH_DIGEST_MD5;
612 else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) &&
613 (pop3c->prefmech & SASL_MECH_CRAM_MD5)) {
614 mech = SASL_MECH_STRING_CRAM_MD5;
615 state1 = POP3_AUTH_CRAMMD5;
616 pop3c->authused = SASL_MECH_CRAM_MD5;
621 if((pop3c->authmechs & SASL_MECH_NTLM) &&
622 (pop3c->prefmech & SASL_MECH_NTLM)) {
623 mech = SASL_MECH_STRING_NTLM;
624 state1 = POP3_AUTH_NTLM;
625 state2 = POP3_AUTH_NTLM_TYPE2MSG;
626 pop3c->authused = SASL_MECH_NTLM;
628 if(data->set.sasl_ir)
629 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
635 if(((pop3c->authmechs & SASL_MECH_XOAUTH2) &&
636 (pop3c->prefmech & SASL_MECH_XOAUTH2) &&
637 (pop3c->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
638 mech = SASL_MECH_STRING_XOAUTH2;
639 state1 = POP3_AUTH_XOAUTH2;
640 state2 = POP3_AUTH_FINAL;
641 pop3c->authused = SASL_MECH_XOAUTH2;
643 if(data->set.sasl_ir)
644 result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
645 conn->xoauth2_bearer,
648 else if((pop3c->authmechs & SASL_MECH_LOGIN) &&
649 (pop3c->prefmech & SASL_MECH_LOGIN)) {
650 mech = SASL_MECH_STRING_LOGIN;
651 state1 = POP3_AUTH_LOGIN;
652 state2 = POP3_AUTH_LOGIN_PASSWD;
653 pop3c->authused = SASL_MECH_LOGIN;
655 if(data->set.sasl_ir)
656 result = Curl_sasl_create_login_message(conn->data, conn->user,
659 else if((pop3c->authmechs & SASL_MECH_PLAIN) &&
660 (pop3c->prefmech & SASL_MECH_PLAIN)) {
661 mech = SASL_MECH_STRING_PLAIN;
662 state1 = POP3_AUTH_PLAIN;
663 state2 = POP3_AUTH_FINAL;
664 pop3c->authused = SASL_MECH_PLAIN;
666 if(data->set.sasl_ir)
667 result = Curl_sasl_create_plain_message(conn->data, conn->user,
668 conn->passwd, &initresp,
674 if(mech && (pop3c->preftype & POP3_TYPE_SASL)) {
675 /* Perform SASL based authentication */
677 8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */
678 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
684 result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
690 Curl_safefree(initresp);
692 #ifndef CURL_DISABLE_CRYPTO_AUTH
693 else if((pop3c->authtypes & POP3_TYPE_APOP) &&
694 (pop3c->preftype & POP3_TYPE_APOP))
695 /* Perform APOP authentication */
696 result = pop3_perform_apop(conn);
698 else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) &&
699 (pop3c->preftype & POP3_TYPE_CLEARTEXT))
700 /* Perform clear text authentication */
701 result = pop3_perform_user(conn);
703 /* Other mechanisms not supported */
704 infof(conn->data, "No known authentication mechanisms supported!\n");
705 result = CURLE_LOGIN_DENIED;
712 /***********************************************************************
714 * pop3_perform_command()
716 * Sends a POP3 based command.
718 static CURLcode pop3_perform_command(struct connectdata *conn)
720 CURLcode result = CURLE_OK;
721 struct SessionHandle *data = conn->data;
722 struct POP3 *pop3 = data->req.protop;
723 const char *command = NULL;
725 /* Calculate the default command */
726 if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
729 if(pop3->id[0] != '\0')
730 /* Message specific LIST so skip the BODY transfer */
731 pop3->transfer = FTPTRANSFER_INFO;
736 /* Send the command */
737 if(pop3->id[0] != '\0')
738 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
739 (pop3->custom && pop3->custom[0] != '\0' ?
740 pop3->custom : command), pop3->id);
742 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s",
743 (pop3->custom && pop3->custom[0] != '\0' ?
744 pop3->custom : command));
747 state(conn, POP3_COMMAND);
752 /***********************************************************************
754 * pop3_perform_quit()
756 * Performs the quit action prior to sclose() be called.
758 static CURLcode pop3_perform_quit(struct connectdata *conn)
760 CURLcode result = CURLE_OK;
762 /* Send the QUIT command */
763 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT");
766 state(conn, POP3_QUIT);
771 /* For the initial server greeting */
772 static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
776 CURLcode result = CURLE_OK;
777 struct SessionHandle *data = conn->data;
779 (void)instate; /* no use for this yet */
781 if(pop3code != '+') {
782 failf(data, "Got unexpected pop3-server response");
783 result = CURLE_FTP_WEIRD_SERVER_REPLY;
786 result = pop3_perform_capa(conn);
791 /* For CAPA responses */
792 static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
795 CURLcode result = CURLE_OK;
796 struct SessionHandle *data = conn->data;
797 struct pop3_conn *pop3c = &conn->proto.pop3c;
799 (void)instate; /* no use for this yet */
802 result = pop3_perform_user(conn);
803 else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
804 /* We don't have a SSL/TLS connection yet, but SSL is requested */
805 if(pop3c->tls_supported)
806 /* Switch to TLS connection now */
807 result = pop3_perform_starttls(conn);
808 else if(data->set.use_ssl == CURLUSESSL_TRY)
809 /* Fallback and carry on with authentication */
810 result = pop3_perform_authentication(conn);
812 failf(data, "STLS not supported.");
813 result = CURLE_USE_SSL_FAILED;
817 result = pop3_perform_authentication(conn);
822 /* For STARTTLS responses */
823 static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
827 CURLcode result = CURLE_OK;
828 struct SessionHandle *data = conn->data;
830 (void)instate; /* no use for this yet */
832 if(pop3code != '+') {
833 if(data->set.use_ssl != CURLUSESSL_TRY) {
834 failf(data, "STARTTLS denied. %c", pop3code);
835 result = CURLE_USE_SSL_FAILED;
838 result = pop3_perform_authentication(conn);
841 result = pop3_perform_upgrade_tls(conn);
846 /* For AUTH PLAIN (without initial response) responses */
847 static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
851 CURLcode result = CURLE_OK;
852 struct SessionHandle *data = conn->data;
854 char *plainauth = NULL;
856 (void)instate; /* no use for this yet */
858 if(pop3code != '+') {
859 failf(data, "Access denied. %c", pop3code);
860 result = CURLE_LOGIN_DENIED;
863 /* Create the authorisation message */
864 result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
866 if(!result && plainauth) {
867 /* Send the message */
868 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth);
871 state(conn, POP3_AUTH_FINAL);
875 Curl_safefree(plainauth);
880 /* For AUTH LOGIN (without initial response) responses */
881 static CURLcode pop3_state_auth_login_resp(struct connectdata *conn,
885 CURLcode result = CURLE_OK;
886 struct SessionHandle *data = conn->data;
888 char *authuser = NULL;
890 (void)instate; /* no use for this yet */
892 if(pop3code != '+') {
893 failf(data, "Access denied: %d", pop3code);
894 result = CURLE_LOGIN_DENIED;
897 /* Create the user message */
898 result = Curl_sasl_create_login_message(data, conn->user,
900 if(!result && authuser) {
902 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser);
905 state(conn, POP3_AUTH_LOGIN_PASSWD);
909 Curl_safefree(authuser);
914 /* For AUTH LOGIN user entry responses */
915 static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn,
919 CURLcode result = CURLE_OK;
920 struct SessionHandle *data = conn->data;
922 char *authpasswd = NULL;
924 (void)instate; /* no use for this yet */
926 if(pop3code != '+') {
927 failf(data, "Access denied: %d", pop3code);
928 result = CURLE_LOGIN_DENIED;
931 /* Create the password message */
932 result = Curl_sasl_create_login_message(data, conn->passwd,
934 if(!result && authpasswd) {
935 /* Send the password */
936 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd);
939 state(conn, POP3_AUTH_FINAL);
943 Curl_safefree(authpasswd);
948 #ifndef CURL_DISABLE_CRYPTO_AUTH
949 /* For AUTH CRAM-MD5 responses */
950 static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn,
954 CURLcode result = CURLE_OK;
955 struct SessionHandle *data = conn->data;
958 char *rplyb64 = NULL;
961 (void)instate; /* no use for this yet */
963 if(pop3code != '+') {
964 failf(data, "Access denied: %d", pop3code);
965 return CURLE_LOGIN_DENIED;
968 /* Get the challenge message */
969 pop3_get_message(data->state.buffer, &chlg64);
971 /* Decode the challenge message */
972 result = Curl_sasl_decode_cram_md5_message(chlg64, &chlg, &len);
974 /* Send the cancellation */
975 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
978 state(conn, POP3_AUTH_CANCEL);
981 /* Create the response message */
982 result = Curl_sasl_create_cram_md5_message(data, chlg, conn->user,
983 conn->passwd, &rplyb64, &len);
984 if(!result && rplyb64) {
985 /* Send the response */
986 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
989 state(conn, POP3_AUTH_FINAL);
994 Curl_safefree(rplyb64);
999 /* For AUTH DIGEST-MD5 challenge responses */
1000 static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn,
1004 CURLcode result = CURLE_OK;
1005 struct SessionHandle *data = conn->data;
1006 char *chlg64 = NULL;
1007 char *rplyb64 = NULL;
1014 (void)instate; /* no use for this yet */
1016 if(pop3code != '+') {
1017 failf(data, "Access denied: %d", pop3code);
1018 return CURLE_LOGIN_DENIED;
1021 /* Get the challenge message */
1022 pop3_get_message(data->state.buffer, &chlg64);
1024 /* Decode the challange message */
1025 result = Curl_sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
1026 realm, sizeof(realm),
1027 algorithm, sizeof(algorithm));
1028 if(result || strcmp(algorithm, "md5-sess") != 0) {
1029 /* Send the cancellation */
1030 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1033 state(conn, POP3_AUTH_CANCEL);
1036 /* Create the response message */
1037 result = Curl_sasl_create_digest_md5_message(data, nonce, realm,
1038 conn->user, conn->passwd,
1039 "pop", &rplyb64, &len);
1040 if(!result && rplyb64) {
1041 /* Send the response */
1042 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
1045 state(conn, POP3_AUTH_DIGESTMD5_RESP);
1049 Curl_safefree(rplyb64);
1054 /* For AUTH DIGEST-MD5 challenge-response responses */
1055 static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn,
1059 CURLcode result = CURLE_OK;
1060 struct SessionHandle *data = conn->data;
1062 (void)instate; /* no use for this yet */
1064 if(pop3code != '+') {
1065 failf(data, "Authentication failed: %d", pop3code);
1066 result = CURLE_LOGIN_DENIED;
1069 /* Send an empty response */
1070 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "");
1073 state(conn, POP3_AUTH_FINAL);
1081 /* For AUTH NTLM (without initial response) responses */
1082 static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn,
1086 CURLcode result = CURLE_OK;
1087 struct SessionHandle *data = conn->data;
1089 char *type1msg = NULL;
1091 (void)instate; /* no use for this yet */
1093 if(pop3code != '+') {
1094 failf(data, "Access denied: %d", pop3code);
1095 result = CURLE_LOGIN_DENIED;
1098 /* Create the type-1 message */
1099 result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
1102 if(!result && type1msg) {
1103 /* Send the message */
1104 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg);
1107 state(conn, POP3_AUTH_NTLM_TYPE2MSG);
1111 Curl_safefree(type1msg);
1116 /* For NTLM type-2 responses (sent in reponse to our type-1 message) */
1117 static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
1121 CURLcode result = CURLE_OK;
1122 struct SessionHandle *data = conn->data;
1123 char *type2msg = NULL;
1124 char *type3msg = NULL;
1127 (void)instate; /* no use for this yet */
1129 if(pop3code != '+') {
1130 failf(data, "Access denied: %d", pop3code);
1131 result = CURLE_LOGIN_DENIED;
1134 /* Get the type-2 message */
1135 pop3_get_message(data->state.buffer, &type2msg);
1137 /* Decode the type-2 message */
1138 result = Curl_sasl_decode_ntlm_type2_message(data, type2msg, &conn->ntlm);
1140 /* Send the cancellation */
1141 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "*");
1144 state(conn, POP3_AUTH_CANCEL);
1147 /* Create the type-3 message */
1148 result = Curl_sasl_create_ntlm_type3_message(data, conn->user,
1149 conn->passwd, &conn->ntlm,
1151 if(!result && type3msg) {
1152 /* Send the message */
1153 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg);
1156 state(conn, POP3_AUTH_FINAL);
1161 Curl_safefree(type3msg);
1167 /* For AUTH XOAUTH2 (without initial response) responses */
1168 static CURLcode pop3_state_auth_xoauth2_resp(struct connectdata *conn,
1169 int pop3code, pop3state instate)
1171 CURLcode result = CURLE_OK;
1172 struct SessionHandle *data = conn->data;
1174 char *xoauth = NULL;
1176 (void)instate; /* no use for this yet */
1178 if(pop3code != '+') {
1179 failf(data, "Access denied: %d", pop3code);
1180 result = CURLE_LOGIN_DENIED;
1183 /* Create the authorisation message */
1184 result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
1185 conn->xoauth2_bearer,
1187 if(!result && xoauth) {
1188 /* Send the message */
1189 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", xoauth);
1192 state(conn, POP3_AUTH_FINAL);
1196 Curl_safefree(xoauth);
1201 /* For AUTH cancellation responses */
1202 static CURLcode pop3_state_auth_cancel_resp(struct connectdata *conn,
1206 struct SessionHandle *data = conn->data;
1209 (void)instate; /* no use for this yet */
1211 failf(data, "Authentication cancelled");
1213 return CURLE_LOGIN_DENIED;
1216 /* For final responses in the AUTH sequence */
1217 static CURLcode pop3_state_auth_final_resp(struct connectdata *conn,
1221 CURLcode result = CURLE_OK;
1222 struct SessionHandle *data = conn->data;
1224 (void)instate; /* no use for this yet */
1226 if(pop3code != '+') {
1227 failf(data, "Authentication failed: %d", pop3code);
1228 result = CURLE_LOGIN_DENIED;
1231 /* End of connect phase */
1232 state(conn, POP3_STOP);
1237 #ifndef CURL_DISABLE_CRYPTO_AUTH
1238 /* For APOP responses */
1239 static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
1242 CURLcode result = CURLE_OK;
1243 struct SessionHandle *data = conn->data;
1245 (void)instate; /* no use for this yet */
1247 if(pop3code != '+') {
1248 failf(data, "Authentication failed: %d", pop3code);
1249 result = CURLE_LOGIN_DENIED;
1252 /* End of connect phase */
1253 state(conn, POP3_STOP);
1259 /* For USER responses */
1260 static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
1263 CURLcode result = CURLE_OK;
1264 struct SessionHandle *data = conn->data;
1266 (void)instate; /* no use for this yet */
1268 if(pop3code != '+') {
1269 failf(data, "Access denied. %c", pop3code);
1270 result = CURLE_LOGIN_DENIED;
1273 /* Send the PASS command */
1274 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
1275 conn->passwd ? conn->passwd : "");
1277 state(conn, POP3_PASS);
1282 /* For PASS responses */
1283 static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
1286 CURLcode result = CURLE_OK;
1287 struct SessionHandle *data = conn->data;
1289 (void)instate; /* no use for this yet */
1291 if(pop3code != '+') {
1292 failf(data, "Access denied. %c", pop3code);
1293 result = CURLE_LOGIN_DENIED;
1296 /* End of connect phase */
1297 state(conn, POP3_STOP);
1302 /* For command responses */
1303 static CURLcode pop3_state_command_resp(struct connectdata *conn,
1307 CURLcode result = CURLE_OK;
1308 struct SessionHandle *data = conn->data;
1309 struct POP3 *pop3 = data->req.protop;
1310 struct pop3_conn *pop3c = &conn->proto.pop3c;
1311 struct pingpong *pp = &pop3c->pp;
1313 (void)instate; /* no use for this yet */
1315 if(pop3code != '+') {
1316 state(conn, POP3_STOP);
1317 return CURLE_RECV_ERROR;
1320 /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
1321 EOB string so count this is two matching bytes. This is necessary to make
1322 the code detect the EOB if the only data than comes now is %2e CR LF like
1323 when there is no body to return. */
1326 /* But since this initial CR LF pair is not part of the actual body, we set
1327 the strip counter here so that these bytes won't be delivered. */
1330 if(pop3->transfer == FTPTRANSFER_BODY) {
1332 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
1335 /* The header "cache" contains a bunch of data that is actually body
1336 content so send it as such. Note that there may even be additional
1337 "headers" after the body */
1339 if(!data->set.opt_no_body) {
1340 result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
1345 /* Free the cache */
1346 Curl_safefree(pp->cache);
1348 /* Reset the cache size */
1353 /* End of DO phase */
1354 state(conn, POP3_STOP);
1359 static CURLcode pop3_statemach_act(struct connectdata *conn)
1361 CURLcode result = CURLE_OK;
1362 curl_socket_t sock = conn->sock[FIRSTSOCKET];
1364 struct pop3_conn *pop3c = &conn->proto.pop3c;
1365 struct pingpong *pp = &pop3c->pp;
1368 /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
1369 if(pop3c->state == POP3_UPGRADETLS)
1370 return pop3_perform_upgrade_tls(conn);
1372 /* Flush any data that needs to be sent */
1374 return Curl_pp_flushsend(pp);
1376 /* Read the response from the server */
1377 result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
1382 /* We have now received a full POP3 server response */
1383 switch(pop3c->state) {
1384 case POP3_SERVERGREET:
1385 result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
1389 result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
1393 result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
1396 case POP3_AUTH_PLAIN:
1397 result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state);
1400 case POP3_AUTH_LOGIN:
1401 result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state);
1404 case POP3_AUTH_LOGIN_PASSWD:
1405 result = pop3_state_auth_login_password_resp(conn, pop3code,
1409 #ifndef CURL_DISABLE_CRYPTO_AUTH
1410 case POP3_AUTH_CRAMMD5:
1411 result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state);
1414 case POP3_AUTH_DIGESTMD5:
1415 result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state);
1418 case POP3_AUTH_DIGESTMD5_RESP:
1419 result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state);
1424 case POP3_AUTH_NTLM:
1425 result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state);
1428 case POP3_AUTH_NTLM_TYPE2MSG:
1429 result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code,
1434 case POP3_AUTH_XOAUTH2:
1435 result = pop3_state_auth_xoauth2_resp(conn, pop3code, pop3c->state);
1438 case POP3_AUTH_CANCEL:
1439 result = pop3_state_auth_cancel_resp(conn, pop3code, pop3c->state);
1442 case POP3_AUTH_FINAL:
1443 result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state);
1446 #ifndef CURL_DISABLE_CRYPTO_AUTH
1448 result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
1453 result = pop3_state_user_resp(conn, pop3code, pop3c->state);
1457 result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
1461 result = pop3_state_command_resp(conn, pop3code, pop3c->state);
1465 /* fallthrough, just stop! */
1467 /* internal error */
1468 state(conn, POP3_STOP);
1476 /* Called repeatedly until done from multi.c */
1477 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
1479 CURLcode result = CURLE_OK;
1480 struct pop3_conn *pop3c = &conn->proto.pop3c;
1482 if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
1483 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
1484 if(result || !pop3c->ssldone)
1488 result = Curl_pp_statemach(&pop3c->pp, FALSE);
1489 *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
1494 static CURLcode pop3_block_statemach(struct connectdata *conn)
1496 CURLcode result = CURLE_OK;
1497 struct pop3_conn *pop3c = &conn->proto.pop3c;
1499 while(pop3c->state != POP3_STOP && !result)
1500 result = Curl_pp_statemach(&pop3c->pp, TRUE);
1505 /* Allocate and initialize the POP3 struct for the current SessionHandle if
1507 static CURLcode pop3_init(struct connectdata *conn)
1509 CURLcode result = CURLE_OK;
1510 struct SessionHandle *data = conn->data;
1513 pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
1515 result = CURLE_OUT_OF_MEMORY;
1520 /* For the POP3 "protocol connect" and "doing" phases only */
1521 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
1524 return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
1527 /***********************************************************************
1531 * This function should do everything that is to be considered a part of the
1534 * The variable 'done' points to will be TRUE if the protocol-layer connect
1535 * phase is done when this function returns, or FALSE if not.
1537 static CURLcode pop3_connect(struct connectdata *conn, bool *done)
1539 CURLcode result = CURLE_OK;
1540 struct pop3_conn *pop3c = &conn->proto.pop3c;
1541 struct pingpong *pp = &pop3c->pp;
1543 *done = FALSE; /* default to not done yet */
1545 /* We always support persistent connections in POP3 */
1546 conn->bits.close = FALSE;
1548 /* Set the default response time-out */
1549 pp->response_time = RESP_TIMEOUT;
1550 pp->statemach_act = pop3_statemach_act;
1551 pp->endofresp = pop3_endofresp;
1554 /* Set the default preferred authentication type and mechanism */
1555 pop3c->preftype = POP3_TYPE_ANY;
1556 pop3c->prefmech = SASL_AUTH_ANY;
1558 /* Initialise the pingpong layer */
1561 /* Parse the URL options */
1562 result = pop3_parse_url_options(conn);
1566 /* Start off waiting for the server greeting response */
1567 state(conn, POP3_SERVERGREET);
1569 result = pop3_multi_statemach(conn, done);
1574 /***********************************************************************
1578 * The DONE function. This does what needs to be done after a single DO has
1581 * Input argument is already checked for validity.
1583 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
1586 CURLcode result = CURLE_OK;
1587 struct SessionHandle *data = conn->data;
1588 struct POP3 *pop3 = data->req.protop;
1593 /* When the easy handle is removed from the multi interface while libcurl
1594 is still trying to resolve the host name, the POP3 struct is not yet
1595 initialized. However, the removal action calls Curl_done() which in
1596 turn calls this function, so we simply return success. */
1600 conn->bits.close = TRUE; /* marked for closure */
1601 result = status; /* use the already set error code */
1604 /* Cleanup our per-request based variables */
1605 Curl_safefree(pop3->id);
1606 Curl_safefree(pop3->custom);
1608 /* Clear the transfer mode for the next request */
1609 pop3->transfer = FTPTRANSFER_BODY;
1614 /***********************************************************************
1618 * This is the actual DO function for POP3. Get a message/listing according to
1619 * the options previously setup.
1621 static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
1624 /* This is POP3 and no proxy */
1625 CURLcode result = CURLE_OK;
1626 struct POP3 *pop3 = conn->data->req.protop;
1628 DEBUGF(infof(conn->data, "DO phase starts\n"));
1630 if(conn->data->set.opt_no_body) {
1631 /* Requested no body means no transfer */
1632 pop3->transfer = FTPTRANSFER_INFO;
1635 *dophase_done = FALSE; /* not done yet */
1637 /* Start the first command in the DO phase */
1638 result = pop3_perform_command(conn);
1642 /* Run the state-machine */
1643 result = pop3_multi_statemach(conn, dophase_done);
1645 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1648 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1653 /***********************************************************************
1657 * This function is registered as 'curl_do' function. It decodes the path
1658 * parts etc as a wrapper to the actual DO function (pop3_perform).
1660 * The input argument is already checked for validity.
1662 static CURLcode pop3_do(struct connectdata *conn, bool *done)
1664 CURLcode result = CURLE_OK;
1666 *done = FALSE; /* default to false */
1668 /* Parse the URL path */
1669 result = pop3_parse_url_path(conn);
1673 /* Parse the custom request */
1674 result = pop3_parse_custom_request(conn);
1678 result = pop3_regular_transfer(conn, done);
1683 /***********************************************************************
1687 * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
1688 * resources. BLOCKING.
1690 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
1692 struct pop3_conn *pop3c = &conn->proto.pop3c;
1694 /* We cannot send quit unconditionally. If this connection is stale or
1695 bad in any way, sending quit and waiting around here will make the
1696 disconnect wait in vain and cause more problems than we need to. */
1698 /* The POP3 session may or may not have been allocated/setup at this
1700 if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
1701 if(!pop3_perform_quit(conn))
1702 (void)pop3_block_statemach(conn); /* ignore errors on QUIT */
1704 /* Disconnect from the server */
1705 Curl_pp_disconnect(&pop3c->pp);
1707 /* Cleanup the SASL module */
1708 Curl_sasl_cleanup(conn, pop3c->authused);
1710 /* Cleanup our connection based variables */
1711 Curl_safefree(pop3c->apoptimestamp);
1716 /* Call this when the DO phase has completed */
1717 static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
1725 /* Called from multi.c while DOing */
1726 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
1728 CURLcode result = pop3_multi_statemach(conn, dophase_done);
1731 DEBUGF(infof(conn->data, "DO phase failed\n"));
1732 else if(*dophase_done) {
1733 result = pop3_dophase_done(conn, FALSE /* not connected */);
1735 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1741 /***********************************************************************
1743 * pop3_regular_transfer()
1745 * The input argument is already checked for validity.
1747 * Performs all commands done before a regular transfer between a local and a
1750 static CURLcode pop3_regular_transfer(struct connectdata *conn,
1753 CURLcode result = CURLE_OK;
1754 bool connected = FALSE;
1755 struct SessionHandle *data = conn->data;
1757 /* Make sure size is unknown at this point */
1758 data->req.size = -1;
1760 /* Set the progress data */
1761 Curl_pgrsSetUploadCounter(data, 0);
1762 Curl_pgrsSetDownloadCounter(data, 0);
1763 Curl_pgrsSetUploadSize(data, 0);
1764 Curl_pgrsSetDownloadSize(data, 0);
1766 /* Carry out the perform */
1767 result = pop3_perform(conn, &connected, dophase_done);
1769 /* Perform post DO phase operations if necessary */
1770 if(!result && *dophase_done)
1771 result = pop3_dophase_done(conn, connected);
1776 static CURLcode pop3_setup_connection(struct connectdata *conn)
1778 struct SessionHandle *data = conn->data;
1780 /* Initialise the POP3 layer */
1781 CURLcode result = pop3_init(conn);
1785 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1786 /* Unless we have asked to tunnel POP3 operations through the proxy, we
1787 switch and use HTTP operations only */
1788 #ifndef CURL_DISABLE_HTTP
1789 if(conn->handler == &Curl_handler_pop3)
1790 conn->handler = &Curl_handler_pop3_proxy;
1793 conn->handler = &Curl_handler_pop3s_proxy;
1795 failf(data, "POP3S not supported!");
1796 return CURLE_UNSUPPORTED_PROTOCOL;
1800 /* set it up as an HTTP connection instead */
1801 return conn->handler->setup_connection(conn);
1803 failf(data, "POP3 over http proxy requires HTTP support built-in!");
1804 return CURLE_UNSUPPORTED_PROTOCOL;
1808 data->state.path++; /* don't include the initial slash */
1813 /***********************************************************************
1815 * pop3_parse_url_options()
1817 * Parse the URL login options.
1819 static CURLcode pop3_parse_url_options(struct connectdata *conn)
1821 CURLcode result = CURLE_OK;
1822 struct pop3_conn *pop3c = &conn->proto.pop3c;
1823 const char *options = conn->options;
1824 const char *ptr = options;
1827 const char *key = ptr;
1829 while(*ptr && *ptr != '=')
1832 if(strnequal(key, "AUTH", 4)) {
1833 const char *value = ptr + 1;
1835 if(strequal(value, "*")) {
1836 pop3c->preftype = POP3_TYPE_ANY;
1837 pop3c->prefmech = SASL_AUTH_ANY;
1839 else if(strequal(value, "+APOP")) {
1840 pop3c->preftype = POP3_TYPE_APOP;
1841 pop3c->prefmech = SASL_AUTH_NONE;
1843 else if(strequal(value, SASL_MECH_STRING_LOGIN)) {
1844 pop3c->preftype = POP3_TYPE_SASL;
1845 pop3c->prefmech = SASL_MECH_LOGIN;
1847 else if(strequal(value, SASL_MECH_STRING_PLAIN)) {
1848 pop3c->preftype = POP3_TYPE_SASL;
1849 pop3c->prefmech = SASL_MECH_PLAIN;
1851 else if(strequal(value, SASL_MECH_STRING_CRAM_MD5)) {
1852 pop3c->preftype = POP3_TYPE_SASL;
1853 pop3c->prefmech = SASL_MECH_CRAM_MD5;
1855 else if(strequal(value, SASL_MECH_STRING_DIGEST_MD5)) {
1856 pop3c->preftype = POP3_TYPE_SASL;
1857 pop3c->prefmech = SASL_MECH_DIGEST_MD5;
1859 else if(strequal(value, SASL_MECH_STRING_GSSAPI)) {
1860 pop3c->preftype = POP3_TYPE_SASL;
1861 pop3c->prefmech = SASL_MECH_GSSAPI;
1863 else if(strequal(value, SASL_MECH_STRING_NTLM)) {
1864 pop3c->preftype = POP3_TYPE_SASL;
1865 pop3c->prefmech = SASL_MECH_NTLM;
1867 else if(strequal(value, SASL_MECH_STRING_XOAUTH2)) {
1868 pop3c->preftype = POP3_TYPE_SASL;
1869 pop3c->prefmech = SASL_MECH_XOAUTH2;
1872 pop3c->preftype = POP3_TYPE_NONE;
1873 pop3c->prefmech = SASL_AUTH_NONE;
1877 result = CURLE_URL_MALFORMAT;
1883 /***********************************************************************
1885 * pop3_parse_url_path()
1887 * Parse the URL path into separate path components.
1889 static CURLcode pop3_parse_url_path(struct connectdata *conn)
1891 /* The POP3 struct is already initialised in pop3_connect() */
1892 struct SessionHandle *data = conn->data;
1893 struct POP3 *pop3 = data->req.protop;
1894 const char *path = data->state.path;
1896 /* URL decode the path for the message ID */
1897 return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
1900 /***********************************************************************
1902 * pop3_parse_custom_request()
1904 * Parse the custom request.
1906 static CURLcode pop3_parse_custom_request(struct connectdata *conn)
1908 CURLcode result = CURLE_OK;
1909 struct SessionHandle *data = conn->data;
1910 struct POP3 *pop3 = data->req.protop;
1911 const char *custom = data->set.str[STRING_CUSTOMREQUEST];
1913 /* URL decode the custom request */
1915 result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
1920 /***********************************************************************
1924 * This function scans the body after the end-of-body and writes everything
1925 * until the end is found.
1927 CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
1929 /* This code could be made into a special function in the handler struct */
1930 CURLcode result = CURLE_OK;
1931 struct SessionHandle *data = conn->data;
1932 struct SingleRequest *k = &data->req;
1934 struct pop3_conn *pop3c = &conn->proto.pop3c;
1935 bool strip_dot = FALSE;
1939 /* Search through the buffer looking for the end-of-body marker which is
1940 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
1941 the eob so the server will have prefixed it with an extra dot which we
1942 need to strip out. Additionally the marker could of course be spread out
1943 over 5 different data chunks. */
1944 for(i = 0; i < nread; i++) {
1945 size_t prev = pop3c->eob;
1949 if(pop3c->eob == 0) {
1953 /* Write out the body part that didn't match */
1954 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
1963 else if(pop3c->eob == 3)
1966 /* If the character match wasn't at position 0 or 3 then restart the
1972 if(pop3c->eob == 1 || pop3c->eob == 4)
1975 /* If the character match wasn't at position 1 or 4 then start the
1983 else if(pop3c->eob == 3) {
1984 /* We have an extra dot after the CRLF which we need to strip off */
1989 /* If the character match wasn't at position 2 then start the search
1999 /* Did we have a partial match which has subsequently failed? */
2000 if(prev && prev >= pop3c->eob) {
2001 /* Strip can only be non-zero for the very first mismatch after CRLF
2002 and then both prev and strip are equal and nothing will be output
2004 while(prev && pop3c->strip) {
2010 /* If the partial match was the CRLF and dot then only write the CRLF
2011 as the server would have inserted the dot */
2012 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB,
2013 strip_dot ? prev - 1 : prev);
2024 if(pop3c->eob == POP3_EOB_LEN) {
2025 /* We have a full match so the transfer is done, however we must transfer
2026 the CRLF at the start of the EOB as this is considered to be part of the
2027 message as per RFC-1939, sect. 3 */
2028 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
2030 k->keepon &= ~KEEP_RECV;
2037 /* While EOB is matching nothing should be output */
2041 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
2048 #endif /* CURL_DISABLE_POP3 */