1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2011, 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 * RFC1939 POP3 protocol
22 * RFC2384 POP URL Scheme
23 * RFC2595 Using TLS with IMAP, POP3 and ACAP
25 ***************************************************************************/
29 #ifndef CURL_DISABLE_POP3
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
45 #include <sys/utsname.h>
55 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
57 #define in_addr_t unsigned long
60 #include <curl/curl.h>
68 #include "http.h" /* for HTTP proxy tunnel stuff */
72 #include "strtoofft.h"
81 #include "strtoofft.h"
82 #include "http_proxy.h"
84 #define _MPRINTF_REPLACE /* use our functions only */
85 #include <curl/mprintf.h>
87 #include "curl_memory.h"
88 /* The last #include file should be: */
91 /* Local API functions */
92 static CURLcode pop3_parse_url_path(struct connectdata *conn);
93 static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
94 static CURLcode pop3_do(struct connectdata *conn, bool *done);
95 static CURLcode pop3_done(struct connectdata *conn,
96 CURLcode, bool premature);
97 static CURLcode pop3_connect(struct connectdata *conn, bool *done);
98 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
99 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
100 static int pop3_getsock(struct connectdata *conn,
101 curl_socket_t *socks,
103 static CURLcode pop3_doing(struct connectdata *conn,
105 static CURLcode pop3_setup_connection(struct connectdata * conn);
108 * POP3 protocol handler.
111 const struct Curl_handler Curl_handler_pop3 = {
113 pop3_setup_connection, /* setup_connection */
115 pop3_done, /* done */
116 ZERO_NULL, /* do_more */
117 pop3_connect, /* connect_it */
118 pop3_multi_statemach, /* connecting */
119 pop3_doing, /* doing */
120 pop3_getsock, /* proto_getsock */
121 pop3_getsock, /* doing_getsock */
122 ZERO_NULL, /* domore_getsock */
123 ZERO_NULL, /* perform_getsock */
124 pop3_disconnect, /* disconnect */
125 ZERO_NULL, /* readwrite */
126 PORT_POP3, /* defport */
127 CURLPROTO_POP3, /* protocol */
128 PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
134 * POP3S protocol handler.
137 const struct Curl_handler Curl_handler_pop3s = {
138 "POP3S", /* scheme */
139 pop3_setup_connection, /* setup_connection */
141 pop3_done, /* done */
142 ZERO_NULL, /* do_more */
143 pop3_connect, /* connect_it */
144 pop3_multi_statemach, /* connecting */
145 pop3_doing, /* doing */
146 pop3_getsock, /* proto_getsock */
147 pop3_getsock, /* doing_getsock */
148 ZERO_NULL, /* domore_getsock */
149 ZERO_NULL, /* perform_getsock */
150 pop3_disconnect, /* disconnect */
151 ZERO_NULL, /* readwrite */
152 PORT_POP3S, /* defport */
153 CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */
154 PROTOPT_CLOSEACTION | PROTOPT_SSL
155 | PROTOPT_NOURLQUERY /* flags */
159 #ifndef CURL_DISABLE_HTTP
161 * HTTP-proxyed POP3 protocol handler.
164 static const struct Curl_handler Curl_handler_pop3_proxy = {
166 ZERO_NULL, /* setup_connection */
167 Curl_http, /* do_it */
168 Curl_http_done, /* done */
169 ZERO_NULL, /* do_more */
170 ZERO_NULL, /* connect_it */
171 ZERO_NULL, /* connecting */
172 ZERO_NULL, /* doing */
173 ZERO_NULL, /* proto_getsock */
174 ZERO_NULL, /* doing_getsock */
175 ZERO_NULL, /* domore_getsock */
176 ZERO_NULL, /* perform_getsock */
177 ZERO_NULL, /* disconnect */
178 ZERO_NULL, /* readwrite */
179 PORT_POP3, /* defport */
180 CURLPROTO_HTTP, /* protocol */
181 PROTOPT_NONE /* flags */
187 * HTTP-proxyed POP3S protocol handler.
190 static const struct Curl_handler Curl_handler_pop3s_proxy = {
191 "POP3S", /* scheme */
192 ZERO_NULL, /* setup_connection */
193 Curl_http, /* do_it */
194 Curl_http_done, /* done */
195 ZERO_NULL, /* do_more */
196 ZERO_NULL, /* connect_it */
197 ZERO_NULL, /* connecting */
198 ZERO_NULL, /* doing */
199 ZERO_NULL, /* proto_getsock */
200 ZERO_NULL, /* doing_getsock */
201 ZERO_NULL, /* domore_getsock */
202 ZERO_NULL, /* perform_getsock */
203 ZERO_NULL, /* disconnect */
204 ZERO_NULL, /* readwrite */
205 PORT_POP3S, /* defport */
206 CURLPROTO_HTTP, /* protocol */
207 PROTOPT_NONE /* flags */
213 /* function that checks for a pop3 status code at the start of the given
215 static int pop3_endofresp(struct pingpong *pp,
218 char *line = pp->linestart_resp;
219 size_t len = pp->nread_resp;
221 if(((len >= 3) && !memcmp("+OK", line, 3)) ||
222 ((len >= 4) && !memcmp("-ERR", line, 4))) {
223 *resp=line[1]; /* O or E */
227 return FALSE; /* nothing for us */
230 /* This is the ONLY way to change POP3 state! */
231 static void state(struct connectdata *conn,
234 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
235 /* for debug purposes */
236 static const char * const names[]={
249 struct pop3_conn *pop3c = &conn->proto.pop3c;
250 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
251 if(pop3c->state != newstate)
252 infof(conn->data, "POP3 %p state change from %s to %s\n",
253 pop3c, names[pop3c->state], names[newstate]);
255 pop3c->state = newstate;
258 static CURLcode pop3_state_user(struct connectdata *conn)
261 struct FTP *pop3 = conn->data->state.proto.pop3;
264 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
265 pop3->user?pop3->user:"");
269 state(conn, POP3_USER);
274 /* For the POP3 "protocol connect" and "doing" phases only */
275 static int pop3_getsock(struct connectdata *conn,
276 curl_socket_t *socks,
279 return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
283 static void pop3_to_pop3s(struct connectdata *conn)
285 conn->handler = &Curl_handler_pop3s;
288 #define pop3_to_pop3s(x) Curl_nop_stmt
291 /* for STARTTLS responses */
292 static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
296 CURLcode result = CURLE_OK;
297 struct SessionHandle *data = conn->data;
298 (void)instate; /* no use for this yet */
300 if(pop3code != 'O') {
301 if(data->set.use_ssl != CURLUSESSL_TRY) {
302 failf(data, "STARTTLS denied. %c", pop3code);
303 result = CURLE_USE_SSL_FAILED;
304 state(conn, POP3_STOP);
307 result = pop3_state_user(conn);
310 /* Curl_ssl_connect is BLOCKING */
311 result = Curl_ssl_connect(conn, FIRSTSOCKET);
312 if(CURLE_OK == result) {
314 result = pop3_state_user(conn);
317 state(conn, POP3_STOP);
323 /* for USER responses */
324 static CURLcode pop3_state_user_resp(struct connectdata *conn,
328 CURLcode result = CURLE_OK;
329 struct SessionHandle *data = conn->data;
330 struct FTP *pop3 = data->state.proto.pop3;
332 (void)instate; /* no use for this yet */
334 if(pop3code != 'O') {
335 failf(data, "Access denied. %c", pop3code);
336 result = CURLE_LOGIN_DENIED;
340 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
341 pop3->passwd?pop3->passwd:"");
345 state(conn, POP3_PASS);
349 /* for PASS responses */
350 static CURLcode pop3_state_pass_resp(struct connectdata *conn,
354 CURLcode result = CURLE_OK;
355 struct SessionHandle *data = conn->data;
356 (void)instate; /* no use for this yet */
358 if(pop3code != 'O') {
359 failf(data, "Access denied. %c", pop3code);
360 result = CURLE_LOGIN_DENIED;
363 state(conn, POP3_STOP);
367 /* for the retr response */
368 static CURLcode pop3_state_retr_resp(struct connectdata *conn,
372 CURLcode result = CURLE_OK;
373 struct SessionHandle *data = conn->data;
374 struct FTP *pop3 = data->state.proto.pop3;
375 struct pop3_conn *pop3c = &conn->proto.pop3c;
376 struct pingpong *pp = &pop3c->pp;
378 (void)instate; /* no use for this yet */
380 if('O' != pop3code) {
381 state(conn, POP3_STOP);
382 return CURLE_RECV_ERROR;
386 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE,
387 pop3->bytecountp, -1, NULL); /* no upload here */
390 /* At this point there is a bunch of data in the header "cache" that is
391 actually body content, send it as body and then skip it. Do note
392 that there may even be additional "headers" after the body. */
394 /* we may get the EOB already here! */
395 result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
399 /* cache is drained */
405 state(conn, POP3_STOP);
410 /* for the list response */
411 static CURLcode pop3_state_list_resp(struct connectdata *conn,
415 CURLcode result = CURLE_OK;
416 struct SessionHandle *data = conn->data;
417 struct FTP *pop3 = data->state.proto.pop3;
418 struct pop3_conn *pop3c = &conn->proto.pop3c;
419 struct pingpong *pp = &pop3c->pp;
421 (void)instate; /* no use for this yet */
423 if('O' != pop3code) {
424 state(conn, POP3_STOP);
425 return CURLE_RECV_ERROR;
428 /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
429 EOB string so count this is two matching bytes. This is necessary to make
430 the code detect the EOB if the only data than comes now is %2e CR LF like
431 when there is no body to return. */
434 /* But since this initial CR LF pair is not part of the actual body, we set
435 the strip counter here so that these bytes won't be delivered. */
439 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, pop3->bytecountp,
440 -1, NULL); /* no upload here */
443 /* cache holds the email ID listing */
445 /* we may get the EOB already here! */
446 result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
450 /* cache is drained */
456 state(conn, POP3_STOP);
460 /* for LIST response with a given message */
461 static CURLcode pop3_state_list_single_resp(struct connectdata *conn,
465 CURLcode result = CURLE_OK;
466 struct SessionHandle *data = conn->data;
467 (void)instate; /* no use for this yet */
469 if(pop3code != 'O') {
470 failf(data, "Invalid message. %c", pop3code);
471 result = CURLE_REMOTE_FILE_NOT_FOUND;
474 state(conn, POP3_STOP);
478 /* start the DO phase for RETR */
479 static CURLcode pop3_retr(struct connectdata *conn)
481 CURLcode result = CURLE_OK;
482 struct pop3_conn *pop3c = &conn->proto.pop3c;
484 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "RETR %s", pop3c->mailbox);
488 state(conn, POP3_RETR);
492 /* start the DO phase for LIST */
493 static CURLcode pop3_list(struct connectdata *conn)
495 CURLcode result = CURLE_OK;
496 struct pop3_conn *pop3c = &conn->proto.pop3c;
498 if(pop3c->mailbox[0] != '\0')
499 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox);
501 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST");
505 if(pop3c->mailbox[0] != '\0')
506 state(conn, POP3_LIST_SINGLE);
508 state(conn, POP3_LIST);
512 static CURLcode pop3_statemach_act(struct connectdata *conn)
515 curl_socket_t sock = conn->sock[FIRSTSOCKET];
516 struct SessionHandle *data=conn->data;
518 struct pop3_conn *pop3c = &conn->proto.pop3c;
519 struct pingpong *pp = &pop3c->pp;
523 return Curl_pp_flushsend(pp);
525 /* we read a piece of response */
526 result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
531 /* we have now received a full POP3 server response */
532 switch(pop3c->state) {
533 case POP3_SERVERGREET:
534 if(pop3code != 'O') {
535 failf(data, "Got unexpected pop3-server response");
536 return CURLE_FTP_WEIRD_SERVER_REPLY;
539 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
540 /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
541 to TLS connection now */
542 result = Curl_pp_sendf(&pop3c->pp, "STLS");
543 state(conn, POP3_STARTTLS);
546 result = pop3_state_user(conn);
552 result = pop3_state_user_resp(conn, pop3code, pop3c->state);
556 result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
560 result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
564 result = pop3_state_retr_resp(conn, pop3code, pop3c->state);
568 result = pop3_state_list_resp(conn, pop3code, pop3c->state);
571 case POP3_LIST_SINGLE:
572 result = pop3_state_list_single_resp(conn, pop3code, pop3c->state);
576 /* fallthrough, just stop! */
579 state(conn, POP3_STOP);
586 /* called repeatedly until done from multi.c */
587 static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
589 struct pop3_conn *pop3c = &conn->proto.pop3c;
590 CURLcode result = Curl_pp_multi_statemach(&pop3c->pp);
592 *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
597 static CURLcode pop3_easy_statemach(struct connectdata *conn)
599 struct pop3_conn *pop3c = &conn->proto.pop3c;
600 struct pingpong *pp = &pop3c->pp;
601 CURLcode result = CURLE_OK;
603 while(pop3c->state != POP3_STOP) {
604 result = Curl_pp_easy_statemach(pp);
613 * Allocate and initialize the struct POP3 for the current SessionHandle. If
616 static CURLcode pop3_init(struct connectdata *conn)
618 struct SessionHandle *data = conn->data;
619 struct FTP *pop3 = data->state.proto.pop3;
621 pop3 = data->state.proto.pop3 = calloc(sizeof(struct FTP), 1);
623 return CURLE_OUT_OF_MEMORY;
626 /* get some initial data into the pop3 struct */
627 pop3->bytecountp = &data->req.bytecount;
629 /* No need to duplicate user+password, the connectdata struct won't change
630 during a session, but we re-init them here since on subsequent inits
631 since the conn struct may have changed or been replaced.
633 pop3->user = conn->user;
634 pop3->passwd = conn->passwd;
640 * pop3_connect() should do everything that is to be considered a part of
641 * the connection phase.
643 * The variable 'done' points to will be TRUE if the protocol-layer connect
644 * phase is done when this function returns, or FALSE is not. When called as
645 * a part of the easy interface, it will always be TRUE.
647 static CURLcode pop3_connect(struct connectdata *conn,
648 bool *done) /* see description above */
651 struct pop3_conn *pop3c = &conn->proto.pop3c;
652 struct SessionHandle *data=conn->data;
653 struct pingpong *pp = &pop3c->pp;
655 *done = FALSE; /* default to not done yet */
657 /* If there already is a protocol-specific struct allocated for this
658 sessionhandle, deal with it */
659 Curl_reset_reqproto(conn);
661 result = pop3_init(conn);
662 if(CURLE_OK != result)
665 /* We always support persistent connections on pop3 */
666 conn->bits.close = FALSE;
668 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
669 pp->statemach_act = pop3_statemach_act;
670 pp->endofresp = pop3_endofresp;
673 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
674 /* for POP3 over HTTP proxy */
675 struct HTTP http_proxy;
676 struct FTP *pop3_save;
679 /* We want "seamless" POP3 operations through HTTP proxy tunnel */
681 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
682 * conn->proto.http; we want POP3 through HTTP and we have to change the
683 * member temporarily for connecting to the HTTP proxy. After
684 * Curl_proxyCONNECT we have to set back the member to the original struct
687 pop3_save = data->state.proto.pop3;
688 memset(&http_proxy, 0, sizeof(http_proxy));
689 data->state.proto.http = &http_proxy;
691 result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
692 conn->host.name, conn->remote_port);
694 data->state.proto.pop3 = pop3_save;
696 if(CURLE_OK != result)
700 if(conn->handler->flags & PROTOPT_SSL) {
702 result = Curl_ssl_connect(conn, FIRSTSOCKET);
707 Curl_pp_init(pp); /* init the response reader stuff */
709 /* When we connect, we start in the state where we await the server greet
711 state(conn, POP3_SERVERGREET);
713 if(data->state.used_interface == Curl_if_multi)
714 result = pop3_multi_statemach(conn, done);
716 result = pop3_easy_statemach(conn);
724 /***********************************************************************
728 * The DONE function. This does what needs to be done after a single DO has
731 * Input argument is already checked for validity.
733 static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
736 struct SessionHandle *data = conn->data;
737 struct FTP *pop3 = data->state.proto.pop3;
738 struct pop3_conn *pop3c = &conn->proto.pop3c;
739 CURLcode result=CURLE_OK;
743 /* When the easy handle is removed from the multi while libcurl is still
744 * trying to resolve the host name, it seems that the pop3 struct is not
745 * yet initialized, but the removal action calls Curl_done() which calls
746 * this function. So we simply return success if no pop3 pointer is set.
751 conn->bits.close = TRUE; /* marked for closure */
752 result = status; /* use the already set error code */
755 Curl_safefree(pop3c->mailbox);
756 pop3c->mailbox = NULL;
758 /* clear these for next connection */
759 pop3->transfer = FTPTRANSFER_BODY;
764 /***********************************************************************
768 * This is the actual DO function for POP3. Get a file/directory according to
769 * the options previously setup.
773 CURLcode pop3_perform(struct connectdata *conn,
774 bool *connected, /* connect status after PASV / PORT */
777 /* this is POP3 and no proxy */
778 CURLcode result=CURLE_OK;
779 struct pop3_conn *pop3c = &conn->proto.pop3c;
781 DEBUGF(infof(conn->data, "DO phase starts\n"));
783 if(conn->data->set.opt_no_body) {
784 /* requested no body means no transfer... */
785 struct FTP *pop3 = conn->data->state.proto.pop3;
786 pop3->transfer = FTPTRANSFER_INFO;
789 *dophase_done = FALSE; /* not done yet */
791 /* start the first command in the DO phase */
792 /* If mailbox is empty, then assume user wants listing for mail IDs,
793 * otherwise, attempt to retrieve the mail-id stored in mailbox
795 if(strlen(pop3c->mailbox) && !conn->data->set.ftp_list_only)
796 result = pop3_retr(conn);
798 result = pop3_list(conn);
802 /* run the state-machine */
803 if(conn->data->state.used_interface == Curl_if_multi)
804 result = pop3_multi_statemach(conn, dophase_done);
806 result = pop3_easy_statemach(conn);
807 *dophase_done = TRUE; /* with the easy interface we are done here */
809 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
812 DEBUGF(infof(conn->data, "DO phase is complete\n"));
817 /***********************************************************************
821 * This function is registered as 'curl_do' function. It decodes the path
822 * parts etc as a wrapper to the actual DO function (pop3_perform).
824 * The input argument is already checked for validity.
826 static CURLcode pop3_do(struct connectdata *conn, bool *done)
828 CURLcode retcode = CURLE_OK;
830 *done = FALSE; /* default to false */
833 Since connections can be re-used between SessionHandles, this might be a
834 connection already existing but on a fresh SessionHandle struct so we must
835 make sure we have a good 'struct POP3' to play with. For new connections,
836 the struct POP3 is allocated and setup in the pop3_connect() function.
838 Curl_reset_reqproto(conn);
839 retcode = pop3_init(conn);
843 retcode = pop3_parse_url_path(conn);
847 retcode = pop3_regular_transfer(conn, done);
852 /***********************************************************************
856 * This should be called before calling sclose(). We should then wait for the
857 * response from the server before returning. The calling code should then try
858 * to close the connection.
861 static CURLcode pop3_quit(struct connectdata *conn)
863 CURLcode result = CURLE_OK;
865 result = Curl_pp_sendf(&conn->proto.pop3c.pp, "QUIT", NULL);
868 state(conn, POP3_QUIT);
870 result = pop3_easy_statemach(conn);
875 /***********************************************************************
879 * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
880 * resources. BLOCKING.
882 static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
884 struct pop3_conn *pop3c= &conn->proto.pop3c;
886 /* We cannot send quit unconditionally. If this connection is stale or
887 bad in any way, sending quit and waiting around here will make the
888 disconnect wait in vain and cause more problems than we need to.
891 /* The POP3 session may or may not have been allocated/setup at this
893 if(!dead_connection && pop3c->pp.conn)
894 (void)pop3_quit(conn); /* ignore errors on the LOGOUT */
897 Curl_pp_disconnect(&pop3c->pp);
902 /***********************************************************************
904 * pop3_parse_url_path()
906 * Parse the URL path into separate path components.
909 static CURLcode pop3_parse_url_path(struct connectdata *conn)
911 /* the pop3 struct is already inited in pop3_connect() */
912 struct pop3_conn *pop3c = &conn->proto.pop3c;
913 struct SessionHandle *data = conn->data;
914 const char *path = data->state.path;
916 /* url decode the path and use this mailbox */
917 return Curl_urldecode(data, path, 0, &pop3c->mailbox, NULL, TRUE);
920 /* call this when the DO phase has completed */
921 static CURLcode pop3_dophase_done(struct connectdata *conn,
924 struct FTP *pop3 = conn->data->state.proto.pop3;
927 if(pop3->transfer != FTPTRANSFER_BODY)
928 /* no data to transfer */
929 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
934 /* called from multi.c while DOing */
935 static CURLcode pop3_doing(struct connectdata *conn,
939 result = pop3_multi_statemach(conn, dophase_done);
942 result = pop3_dophase_done(conn, FALSE /* not connected */);
944 DEBUGF(infof(conn->data, "DO phase is complete\n"));
949 /***********************************************************************
951 * pop3_regular_transfer()
953 * The input argument is already checked for validity.
955 * Performs all commands done before a regular transfer between a local and a
960 CURLcode pop3_regular_transfer(struct connectdata *conn,
963 CURLcode result=CURLE_OK;
964 bool connected=FALSE;
965 struct SessionHandle *data = conn->data;
966 data->req.size = -1; /* make sure this is unknown at this point */
968 Curl_pgrsSetUploadCounter(data, 0);
969 Curl_pgrsSetDownloadCounter(data, 0);
970 Curl_pgrsSetUploadSize(data, 0);
971 Curl_pgrsSetDownloadSize(data, 0);
973 result = pop3_perform(conn,
974 &connected, /* have we connected after PASV/PORT */
975 dophase_done); /* all commands in the DO-phase done? */
977 if(CURLE_OK == result) {
980 /* the DO phase has not completed yet */
983 result = pop3_dophase_done(conn, connected);
991 static CURLcode pop3_setup_connection(struct connectdata * conn)
993 struct SessionHandle *data = conn->data;
995 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
996 /* Unless we have asked to tunnel pop3 operations through the proxy, we
997 switch and use HTTP operations only */
998 #ifndef CURL_DISABLE_HTTP
999 if(conn->handler == &Curl_handler_pop3)
1000 conn->handler = &Curl_handler_pop3_proxy;
1003 conn->handler = &Curl_handler_pop3s_proxy;
1005 failf(data, "POP3S not supported!");
1006 return CURLE_UNSUPPORTED_PROTOCOL;
1010 * We explicitly mark this connection as persistent here as we're doing
1011 * POP3 over HTTP and thus we accidentally avoid setting this value
1014 conn->bits.close = FALSE;
1016 failf(data, "POP3 over http proxy requires HTTP support built-in!");
1017 return CURLE_UNSUPPORTED_PROTOCOL;
1021 data->state.path++; /* don't include the initial slash */
1026 /* this is the 5-bytes End-Of-Body marker for POP3 */
1027 #define POP3_EOB "\x0d\x0a\x2e\x0d\x0a"
1028 #define POP3_EOB_LEN 5
1031 * This function scans the body after the end-of-body and writes everything
1032 * until the end is found.
1034 CURLcode Curl_pop3_write(struct connectdata *conn,
1038 /* This code could be made into a special function in the handler struct. */
1039 CURLcode result = CURLE_OK;
1040 struct SessionHandle *data = conn->data;
1041 struct SingleRequest *k = &data->req;
1043 struct pop3_conn *pop3c = &conn->proto.pop3c;
1044 bool strip_dot = FALSE;
1048 /* Search through the buffer looking for the end-of-body marker which is
1049 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
1050 the eob so the server will have prefixed it with an extra dot which we
1051 need to strip out. Additionally the marker could of course be spread out
1052 over 5 different data chunks */
1053 for(i = 0; i < nread; i++) {
1054 size_t prev = pop3c->eob;
1058 if(pop3c->eob == 0) {
1062 /* Write out the body part that didn't match */
1063 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
1072 else if(pop3c->eob == 3)
1075 /* If the character match wasn't at position 0 or 3 then restart the
1081 if(pop3c->eob == 1 || pop3c->eob == 4)
1084 /* If the character match wasn't at position 1 or 4 then start the
1092 else if(pop3c->eob == 3) {
1093 /* We have an extra dot after the CRLF which we need to strip off */
1098 /* If the character match wasn't at position 2 then start the search
1108 /* Did we have a partial match which has subsequently failed? */
1109 if(prev && prev >= pop3c->eob) {
1110 /* Strip can only be non-zero for the very first mismatch after CRLF
1111 and then both prev and strip are equal and nothing will be output
1113 while(prev && pop3c->strip) {
1119 /* If the partial match was the CRLF and dot then only write the CRLF
1120 as the server would have inserted the dot */
1121 result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB,
1122 strip_dot ? prev - 1 : prev);
1133 if(pop3c->eob == POP3_EOB_LEN) {
1134 /* We have a full match so the transfer is done! */
1135 k->keepon &= ~KEEP_RECV;
1141 /* While EOB is matching nothing should be output */
1145 result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
1152 #endif /* CURL_DISABLE_POP3 */