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 * RFC3501 IMAPv4 protocol
22 * RFC5092 IMAP URL Scheme
24 ***************************************************************************/
28 #ifndef CURL_DISABLE_IMAP
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
44 #include <sys/utsname.h>
54 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
56 #define in_addr_t unsigned long
59 #include <curl/curl.h>
67 #include "http.h" /* for HTTP proxy tunnel stuff */
71 #include "strtoofft.h"
80 #include "strtoofft.h"
81 #include "http_proxy.h"
83 #define _MPRINTF_REPLACE /* use our functions only */
84 #include <curl/mprintf.h>
86 #include "curl_memory.h"
87 /* The last #include file should be: */
90 /* Local API functions */
91 static CURLcode imap_parse_url_path(struct connectdata *conn);
92 static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done);
93 static CURLcode imap_do(struct connectdata *conn, bool *done);
94 static CURLcode imap_done(struct connectdata *conn,
95 CURLcode, bool premature);
96 static CURLcode imap_connect(struct connectdata *conn, bool *done);
97 static CURLcode imap_disconnect(struct connectdata *conn, bool dead);
98 static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
99 static int imap_getsock(struct connectdata *conn,
100 curl_socket_t *socks,
102 static CURLcode imap_doing(struct connectdata *conn,
104 static CURLcode imap_setup_connection(struct connectdata * conn);
105 static CURLcode imap_state_upgrade_tls(struct connectdata *conn);
108 * IMAP protocol handler.
111 const struct Curl_handler Curl_handler_imap = {
113 imap_setup_connection, /* setup_connection */
115 imap_done, /* done */
116 ZERO_NULL, /* do_more */
117 imap_connect, /* connect_it */
118 imap_multi_statemach, /* connecting */
119 imap_doing, /* doing */
120 imap_getsock, /* proto_getsock */
121 imap_getsock, /* doing_getsock */
122 ZERO_NULL, /* domore_getsock */
123 ZERO_NULL, /* perform_getsock */
124 imap_disconnect, /* disconnect */
125 ZERO_NULL, /* readwrite */
126 PORT_IMAP, /* defport */
127 CURLPROTO_IMAP, /* protocol */
128 PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
129 | PROTOPT_NOURLQUERY /* flags */
135 * IMAPS protocol handler.
138 const struct Curl_handler Curl_handler_imaps = {
139 "IMAPS", /* scheme */
140 imap_setup_connection, /* setup_connection */
142 imap_done, /* done */
143 ZERO_NULL, /* do_more */
144 imap_connect, /* connect_it */
145 imap_multi_statemach, /* connecting */
146 imap_doing, /* doing */
147 imap_getsock, /* proto_getsock */
148 imap_getsock, /* doing_getsock */
149 ZERO_NULL, /* domore_getsock */
150 ZERO_NULL, /* perform_getsock */
151 imap_disconnect, /* disconnect */
152 ZERO_NULL, /* readwrite */
153 PORT_IMAPS, /* defport */
154 CURLPROTO_IMAP | CURLPROTO_IMAPS, /* protocol */
155 PROTOPT_CLOSEACTION | PROTOPT_SSL | PROTOPT_NEEDSPWD
156 | PROTOPT_NOURLQUERY /* flags */
160 #ifndef CURL_DISABLE_HTTP
162 * HTTP-proxyed IMAP protocol handler.
165 static const struct Curl_handler Curl_handler_imap_proxy = {
167 ZERO_NULL, /* setup_connection */
168 Curl_http, /* do_it */
169 Curl_http_done, /* done */
170 ZERO_NULL, /* do_more */
171 ZERO_NULL, /* connect_it */
172 ZERO_NULL, /* connecting */
173 ZERO_NULL, /* doing */
174 ZERO_NULL, /* proto_getsock */
175 ZERO_NULL, /* doing_getsock */
176 ZERO_NULL, /* domore_getsock */
177 ZERO_NULL, /* perform_getsock */
178 ZERO_NULL, /* disconnect */
179 ZERO_NULL, /* readwrite */
180 PORT_IMAP, /* defport */
181 CURLPROTO_HTTP, /* protocol */
182 PROTOPT_NONE /* flags */
188 * HTTP-proxyed IMAPS protocol handler.
191 static const struct Curl_handler Curl_handler_imaps_proxy = {
192 "IMAPS", /* scheme */
193 ZERO_NULL, /* 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_IMAPS, /* defport */
207 CURLPROTO_HTTP, /* protocol */
208 PROTOPT_NONE /* flags */
213 /***********************************************************************
217 * Sends the formated string as an IMAP command to a server
219 * Designed to never block.
221 static CURLcode imapsendf(struct connectdata *conn,
222 const char *idstr, /* id to wait for at the
223 completion of this command */
224 const char *fmt, ...)
227 struct imap_conn *imapc = &conn->proto.imapc;
231 imapc->idstr = idstr; /* this is the thing */
233 res = Curl_pp_vsendf(&imapc->pp, fmt, ap);
240 static const char *getcmdid(struct connectdata *conn)
242 static const char * const ids[]= {
249 struct imap_conn *imapc = &conn->proto.imapc;
251 /* get the next id, but wrap at end of table */
252 imapc->cmdid = (int)((imapc->cmdid+1) % (sizeof(ids)/sizeof(ids[0])));
254 return ids[imapc->cmdid];
257 /* For the IMAP "protocol connect" and "doing" phases only */
258 static int imap_getsock(struct connectdata *conn,
259 curl_socket_t *socks,
262 return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks);
265 /* function that checks for an imap status code at the start of the
267 static int imap_endofresp(struct pingpong *pp, int *resp)
269 char *line = pp->linestart_resp;
270 size_t len = pp->nread_resp;
271 struct imap_conn *imapc = &pp->conn->proto.imapc;
272 const char *id = imapc->idstr;
273 size_t id_len = strlen(id);
275 if(len >= id_len + 3) {
276 if(!memcmp(id, line, id_len) && (line[id_len] == ' ') ) {
277 /* end of response */
278 *resp = line[id_len+1]; /* O, N or B */
281 else if((imapc->state == IMAP_FETCH) &&
282 !memcmp("* ", line, 2) ) {
283 /* FETCH response we're interested in */
288 return FALSE; /* nothing for us */
291 /* This is the ONLY way to change IMAP state! */
292 static void state(struct connectdata *conn,
295 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
296 /* for debug purposes */
297 static const char * const names[]={
309 struct imap_conn *imapc = &conn->proto.imapc;
310 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
311 if(imapc->state != newstate)
312 infof(conn->data, "IMAP %p state change from %s to %s\n",
313 imapc, names[imapc->state], names[newstate]);
315 imapc->state = newstate;
318 static CURLcode imap_state_login(struct connectdata *conn)
321 struct FTP *imap = conn->data->state.proto.imap;
324 str = getcmdid(conn);
326 /* send USER and password */
327 result = imapsendf(conn, str, "%s LOGIN %s %s", str,
328 imap->user?imap->user:"",
329 imap->passwd?imap->passwd:"");
333 state(conn, IMAP_LOGIN);
339 static void imap_to_imaps(struct connectdata *conn)
341 conn->handler = &Curl_handler_imaps;
344 #define imap_to_imaps(x) Curl_nop_stmt
347 /* for STARTTLS responses */
348 static CURLcode imap_state_starttls_resp(struct connectdata *conn,
352 CURLcode result = CURLE_OK;
353 struct SessionHandle *data = conn->data;
354 (void)instate; /* no use for this yet */
356 if(imapcode != 'O') {
357 if(data->set.use_ssl != CURLUSESSL_TRY) {
358 failf(data, "STARTTLS denied. %c", imapcode);
359 result = CURLE_USE_SSL_FAILED;
362 result = imap_state_login(conn);
365 if(data->state.used_interface == Curl_if_multi) {
366 state(conn, IMAP_UPGRADETLS);
367 return imap_state_upgrade_tls(conn);
370 result = Curl_ssl_connect(conn, FIRSTSOCKET);
371 if(CURLE_OK == result) {
373 result = imap_state_login(conn);
377 state(conn, IMAP_STOP);
381 static CURLcode imap_state_upgrade_tls(struct connectdata *conn)
383 struct imap_conn *imapc = &conn->proto.imapc;
386 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
390 result = imap_state_login(conn);
391 state(conn, IMAP_STOP);
397 /* for LOGIN responses */
398 static CURLcode imap_state_login_resp(struct connectdata *conn,
402 CURLcode result = CURLE_OK;
403 struct SessionHandle *data = conn->data;
404 (void)instate; /* no use for this yet */
406 if(imapcode != 'O') {
407 failf(data, "Access denied. %c", imapcode);
408 result = CURLE_LOGIN_DENIED;
411 state(conn, IMAP_STOP);
415 /* for the (first line of) FETCH BODY[TEXT] response */
416 static CURLcode imap_state_fetch_resp(struct connectdata *conn,
420 CURLcode result = CURLE_OK;
421 struct SessionHandle *data = conn->data;
422 struct imap_conn *imapc = &conn->proto.imapc;
423 struct FTP *imap = data->state.proto.imap;
424 struct pingpong *pp = &imapc->pp;
425 const char *ptr = data->state.buffer;
426 (void)instate; /* no use for this yet */
428 if('*' != imapcode) {
429 Curl_pgrsSetDownloadSize(data, 0);
430 state(conn, IMAP_STOP);
434 /* Something like this comes "* 1 FETCH (BODY[TEXT] {2021}\r" */
435 while(*ptr && (*ptr != '{'))
439 curl_off_t filesize = curlx_strtoofft(ptr+1, NULL, 10);
441 Curl_pgrsSetDownloadSize(data, filesize);
443 infof(data, "Found %" FORMAT_OFF_TU " bytes to download\n", filesize);
446 /* At this point there is a bunch of data in the header "cache" that is
447 actually body content, send it as body and then skip it. Do note
448 that there may even be additional "headers" after the body. */
449 size_t chunk = pp->cache_size;
451 if(chunk > (size_t)filesize)
452 /* the conversion from curl_off_t to size_t is always fine here */
453 chunk = (size_t)filesize;
455 result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
461 /* we've now used parts of or the entire cache */
462 if(pp->cache_size > chunk) {
463 /* part of, move the trailing data to the start and reduce the size */
464 memmove(pp->cache, pp->cache+chunk,
465 pp->cache_size - chunk);
466 pp->cache_size -= chunk;
469 /* cache is drained */
476 infof(data, "Filesize left: %" FORMAT_OFF_T "\n", filesize);
479 /* the entire data is already transferred! */
480 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
483 Curl_setup_transfer(conn, FIRSTSOCKET, filesize, FALSE,
484 imap->bytecountp, -1, NULL); /* no upload here */
486 data->req.maxdownload = filesize;
489 /* We don't know how to parse this line */
490 result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */
492 state(conn, IMAP_STOP);
496 /* start the DO phase */
497 static CURLcode imap_select(struct connectdata *conn)
499 CURLcode result = CURLE_OK;
500 struct imap_conn *imapc = &conn->proto.imapc;
503 str = getcmdid(conn);
505 result = imapsendf(conn, str, "%s SELECT %s", str,
506 imapc->mailbox?imapc->mailbox:"");
510 state(conn, IMAP_SELECT);
514 static CURLcode imap_fetch(struct connectdata *conn)
516 CURLcode result = CURLE_OK;
519 str = getcmdid(conn);
521 /* TODO: make this select the correct mail
522 * Use "1 body[text]" to get the full mail body of mail 1
524 result = imapsendf(conn, str, "%s FETCH 1 BODY[TEXT]", str);
529 * When issued, the server will respond with a single line similar to
530 * '* 1 FETCH (BODY[TEXT] {2021}'
532 * Identifying the fetch and how many bytes of contents we can expect. We
533 * must extract that number before continuing to "download as usual".
536 state(conn, IMAP_FETCH);
540 /* for SELECT responses */
541 static CURLcode imap_state_select_resp(struct connectdata *conn,
545 CURLcode result = CURLE_OK;
546 struct SessionHandle *data = conn->data;
547 (void)instate; /* no use for this yet */
549 if(imapcode != 'O') {
550 failf(data, "Select failed");
551 result = CURLE_LOGIN_DENIED;
554 result = imap_fetch(conn);
558 static CURLcode imap_statemach_act(struct connectdata *conn)
561 curl_socket_t sock = conn->sock[FIRSTSOCKET];
562 struct SessionHandle *data=conn->data;
564 struct imap_conn *imapc = &conn->proto.imapc;
565 struct pingpong *pp = &imapc->pp;
568 /* busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */
569 if(imapc->state == IMAP_UPGRADETLS)
570 return imap_state_upgrade_tls(conn);
573 return Curl_pp_flushsend(pp);
575 /* we read a piece of response */
576 result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
581 /* we have now received a full IMAP server response */
582 switch(imapc->state) {
583 case IMAP_SERVERGREET:
584 if(imapcode != 'O') {
585 failf(data, "Got unexpected imap-server response");
586 return CURLE_FTP_WEIRD_SERVER_REPLY;
589 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
590 /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
591 to TLS connection now */
594 str = getcmdid(conn);
595 result = imapsendf(conn, str, "%s STARTTLS", str);
596 state(conn, IMAP_STARTTLS);
599 result = imap_state_login(conn);
605 result = imap_state_login_resp(conn, imapcode, imapc->state);
609 result = imap_state_starttls_resp(conn, imapcode, imapc->state);
613 result = imap_state_fetch_resp(conn, imapcode, imapc->state);
617 result = imap_state_select_resp(conn, imapcode, imapc->state);
621 /* fallthrough, just stop! */
624 state(conn, IMAP_STOP);
631 /* called repeatedly until done from multi.c */
632 static CURLcode imap_multi_statemach(struct connectdata *conn,
635 struct imap_conn *imapc = &conn->proto.imapc;
638 if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone)
639 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
641 result = Curl_pp_multi_statemach(&imapc->pp);
643 *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
648 static CURLcode imap_easy_statemach(struct connectdata *conn)
650 struct imap_conn *imapc = &conn->proto.imapc;
651 struct pingpong *pp = &imapc->pp;
652 CURLcode result = CURLE_OK;
654 while(imapc->state != IMAP_STOP) {
655 result = Curl_pp_easy_statemach(pp);
664 * Allocate and initialize the struct IMAP for the current SessionHandle. If
667 static CURLcode imap_init(struct connectdata *conn)
669 struct SessionHandle *data = conn->data;
670 struct FTP *imap = data->state.proto.imap;
672 imap = data->state.proto.imap = calloc(sizeof(struct FTP), 1);
674 return CURLE_OUT_OF_MEMORY;
677 /* get some initial data into the imap struct */
678 imap->bytecountp = &data->req.bytecount;
680 /* No need to duplicate user+password, the connectdata struct won't change
681 during a session, but we re-init them here since on subsequent inits
682 since the conn struct may have changed or been replaced.
684 imap->user = conn->user;
685 imap->passwd = conn->passwd;
691 * imap_connect() should do everything that is to be considered a part of
692 * the connection phase.
694 * The variable 'done' points to will be TRUE if the protocol-layer connect
695 * phase is done when this function returns, or FALSE is not. When called as
696 * a part of the easy interface, it will always be TRUE.
698 static CURLcode imap_connect(struct connectdata *conn,
699 bool *done) /* see description above */
702 struct imap_conn *imapc = &conn->proto.imapc;
703 struct SessionHandle *data=conn->data;
704 struct pingpong *pp = &imapc->pp;
706 *done = FALSE; /* default to not done yet */
708 /* If there already is a protocol-specific struct allocated for this
709 sessionhandle, deal with it */
710 Curl_reset_reqproto(conn);
712 result = imap_init(conn);
713 if(CURLE_OK != result)
716 /* We always support persistent connections on imap */
717 conn->bits.close = FALSE;
719 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
720 pp->statemach_act = imap_statemach_act;
721 pp->endofresp = imap_endofresp;
724 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
725 /* for IMAP over HTTP proxy */
726 struct HTTP http_proxy;
727 struct FTP *imap_save;
730 /* We want "seamless" IMAP operations through HTTP proxy tunnel */
732 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
733 * conn->proto.http; we want IMAP through HTTP and we have to change the
734 * member temporarily for connecting to the HTTP proxy. After
735 * Curl_proxyCONNECT we have to set back the member to the original struct
738 imap_save = data->state.proto.imap;
739 memset(&http_proxy, 0, sizeof(http_proxy));
740 data->state.proto.http = &http_proxy;
742 result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
743 conn->host.name, conn->remote_port);
745 data->state.proto.imap = imap_save;
747 if(CURLE_OK != result)
751 if((conn->handler->flags & PROTOPT_SSL) &&
752 data->state.used_interface != Curl_if_multi) {
754 result = Curl_ssl_connect(conn, FIRSTSOCKET);
759 Curl_pp_init(pp); /* init generic pingpong data */
761 /* When we connect, we start in the state where we await the server greeting
763 state(conn, IMAP_SERVERGREET);
764 imapc->idstr = "*"; /* we start off waiting for a '*' response */
766 if(data->state.used_interface == Curl_if_multi)
767 result = imap_multi_statemach(conn, done);
769 result = imap_easy_statemach(conn);
777 /***********************************************************************
781 * The DONE function. This does what needs to be done after a single DO has
784 * Input argument is already checked for validity.
786 static CURLcode imap_done(struct connectdata *conn, CURLcode status,
789 struct SessionHandle *data = conn->data;
790 struct FTP *imap = data->state.proto.imap;
791 CURLcode result=CURLE_OK;
795 /* When the easy handle is removed from the multi while libcurl is still
796 * trying to resolve the host name, it seems that the imap struct is not
797 * yet initialized, but the removal action calls Curl_done() which calls
798 * this function. So we simply return success if no imap pointer is set.
803 conn->bits.close = TRUE; /* marked for closure */
804 result = status; /* use the already set error code */
807 /* clear these for next connection */
808 imap->transfer = FTPTRANSFER_BODY;
813 /***********************************************************************
817 * This is the actual DO function for IMAP. Get a file/directory according to
818 * the options previously setup.
822 CURLcode imap_perform(struct connectdata *conn,
823 bool *connected, /* connect status after PASV / PORT */
826 /* this is IMAP and no proxy */
827 CURLcode result=CURLE_OK;
829 DEBUGF(infof(conn->data, "DO phase starts\n"));
831 if(conn->data->set.opt_no_body) {
832 /* requested no body means no transfer... */
833 struct FTP *imap = conn->data->state.proto.imap;
834 imap->transfer = FTPTRANSFER_INFO;
837 *dophase_done = FALSE; /* not done yet */
839 /* start the first command in the DO phase */
840 result = imap_select(conn);
844 /* run the state-machine */
845 if(conn->data->state.used_interface == Curl_if_multi)
846 result = imap_multi_statemach(conn, dophase_done);
848 result = imap_easy_statemach(conn);
849 *dophase_done = TRUE; /* with the easy interface we are done here */
851 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
854 DEBUGF(infof(conn->data, "DO phase is complete\n"));
859 /***********************************************************************
863 * This function is registered as 'curl_do' function. It decodes the path
864 * parts etc as a wrapper to the actual DO function (imap_perform).
866 * The input argument is already checked for validity.
868 static CURLcode imap_do(struct connectdata *conn, bool *done)
870 CURLcode retcode = CURLE_OK;
872 *done = FALSE; /* default to false */
875 Since connections can be re-used between SessionHandles, this might be a
876 connection already existing but on a fresh SessionHandle struct so we must
877 make sure we have a good 'struct IMAP' to play with. For new connections,
878 the struct IMAP is allocated and setup in the imap_connect() function.
880 Curl_reset_reqproto(conn);
881 retcode = imap_init(conn);
885 retcode = imap_parse_url_path(conn);
889 retcode = imap_regular_transfer(conn, done);
894 /***********************************************************************
898 * This should be called before calling sclose(). We should then wait for the
899 * response from the server before returning. The calling code should then try
900 * to close the connection.
903 static CURLcode imap_logout(struct connectdata *conn)
905 CURLcode result = CURLE_OK;
908 str = getcmdid(conn);
910 result = imapsendf(conn, str, "%s LOGOUT", str, NULL);
913 state(conn, IMAP_LOGOUT);
915 result = imap_easy_statemach(conn);
920 /***********************************************************************
924 * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
925 * resources. BLOCKING.
927 static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
929 struct imap_conn *imapc= &conn->proto.imapc;
931 /* The IMAP session may or may not have been allocated/setup at this
933 if(!dead_connection && imapc->pp.conn)
934 (void)imap_logout(conn); /* ignore errors on the LOGOUT */
936 Curl_pp_disconnect(&imapc->pp);
938 Curl_safefree(imapc->mailbox);
943 /***********************************************************************
945 * imap_parse_url_path()
947 * Parse the URL path into separate path components.
950 static CURLcode imap_parse_url_path(struct connectdata *conn)
952 /* the imap struct is already inited in imap_connect() */
953 struct imap_conn *imapc = &conn->proto.imapc;
954 struct SessionHandle *data = conn->data;
955 const char *path = data->state.path;
960 /* url decode the path and use this mailbox */
961 return Curl_urldecode(data, path, 0, &imapc->mailbox, NULL, TRUE);
964 /* call this when the DO phase has completed */
965 static CURLcode imap_dophase_done(struct connectdata *conn,
968 struct FTP *imap = conn->data->state.proto.imap;
971 if(imap->transfer != FTPTRANSFER_BODY)
972 /* no data to transfer */
973 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
978 /* called from multi.c while DOing */
979 static CURLcode imap_doing(struct connectdata *conn,
983 result = imap_multi_statemach(conn, dophase_done);
986 result = imap_dophase_done(conn, FALSE /* not connected */);
988 DEBUGF(infof(conn->data, "DO phase is complete\n"));
993 /***********************************************************************
995 * imap_regular_transfer()
997 * The input argument is already checked for validity.
999 * Performs all commands done before a regular transfer between a local and a
1004 CURLcode imap_regular_transfer(struct connectdata *conn,
1007 CURLcode result=CURLE_OK;
1008 bool connected=FALSE;
1009 struct SessionHandle *data = conn->data;
1010 data->req.size = -1; /* make sure this is unknown at this point */
1012 Curl_pgrsSetUploadCounter(data, 0);
1013 Curl_pgrsSetDownloadCounter(data, 0);
1014 Curl_pgrsSetUploadSize(data, 0);
1015 Curl_pgrsSetDownloadSize(data, 0);
1017 result = imap_perform(conn,
1018 &connected, /* have we connected after PASV/PORT */
1019 dophase_done); /* all commands in the DO-phase done? */
1021 if(CURLE_OK == result) {
1024 /* the DO phase has not completed yet */
1027 result = imap_dophase_done(conn, connected);
1035 static CURLcode imap_setup_connection(struct connectdata * conn)
1037 struct SessionHandle *data = conn->data;
1039 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1040 /* Unless we have asked to tunnel imap operations through the proxy, we
1041 switch and use HTTP operations only */
1042 #ifndef CURL_DISABLE_HTTP
1043 if(conn->handler == &Curl_handler_imap)
1044 conn->handler = &Curl_handler_imap_proxy;
1047 conn->handler = &Curl_handler_imaps_proxy;
1049 failf(data, "IMAPS not supported!");
1050 return CURLE_UNSUPPORTED_PROTOCOL;
1054 * We explicitly mark this connection as persistent here as we're doing
1055 * IMAP over HTTP and thus we accidentally avoid setting this value
1058 conn->bits.close = FALSE;
1060 failf(data, "IMAP over http proxy requires HTTP support built-in!");
1061 return CURLE_UNSUPPORTED_PROTOCOL;
1065 data->state.path++; /* don't include the initial slash */
1070 #endif /* CURL_DISABLE_IMAP */