1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2010, 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
39 #ifdef HAVE_SYS_SOCKET_H
40 #include <sys/socket.h>
42 #ifdef HAVE_NETINET_IN_H
43 #include <netinet/in.h>
45 #ifdef HAVE_ARPA_INET_H
46 #include <arpa/inet.h>
49 #include <sys/utsname.h>
59 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
61 #define in_addr_t unsigned long
64 #include <curl/curl.h>
67 #include "easyif.h" /* for Curl_convert_... prototypes */
74 #include "http.h" /* for HTTP proxy tunnel stuff */
78 #include "strtoofft.h"
87 #include "strtoofft.h"
89 #define _MPRINTF_REPLACE /* use our functions only */
90 #include <curl/mprintf.h>
92 #include "curl_memory.h"
93 /* The last #include file should be: */
96 /* Local API functions */
97 static CURLcode imap_parse_url_path(struct connectdata *conn);
98 static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done);
99 static CURLcode imap_do(struct connectdata *conn, bool *done);
100 static CURLcode imap_done(struct connectdata *conn,
101 CURLcode, bool premature);
102 static CURLcode imap_connect(struct connectdata *conn, bool *done);
103 static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection);
104 static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
105 static int imap_getsock(struct connectdata *conn,
106 curl_socket_t *socks,
108 static CURLcode imap_doing(struct connectdata *conn,
110 static CURLcode imap_setup_connection(struct connectdata * conn);
113 * IMAP protocol handler.
116 const struct Curl_handler Curl_handler_imap = {
118 imap_setup_connection, /* setup_connection */
120 imap_done, /* done */
121 ZERO_NULL, /* do_more */
122 imap_connect, /* connect_it */
123 imap_multi_statemach, /* connecting */
124 imap_doing, /* doing */
125 imap_getsock, /* proto_getsock */
126 imap_getsock, /* doing_getsock */
127 ZERO_NULL, /* perform_getsock */
128 imap_disconnect, /* disconnect */
129 PORT_IMAP, /* defport */
130 PROT_IMAP /* protocol */
136 * IMAPS protocol handler.
139 const struct Curl_handler Curl_handler_imaps = {
140 "IMAPS", /* scheme */
141 imap_setup_connection, /* setup_connection */
143 imap_done, /* done */
144 ZERO_NULL, /* do_more */
145 imap_connect, /* connect_it */
146 imap_multi_statemach, /* connecting */
147 imap_doing, /* doing */
148 imap_getsock, /* proto_getsock */
149 imap_getsock, /* doing_getsock */
150 ZERO_NULL, /* perform_getsock */
151 imap_disconnect, /* disconnect */
152 PORT_IMAPS, /* defport */
153 PROT_IMAP | PROT_IMAPS | PROT_SSL /* protocol */
157 #ifndef CURL_DISABLE_HTTP
159 * HTTP-proxyed IMAP protocol handler.
162 static const struct Curl_handler Curl_handler_imap_proxy = {
164 ZERO_NULL, /* setup_connection */
165 Curl_http, /* do_it */
166 Curl_http_done, /* done */
167 ZERO_NULL, /* do_more */
168 ZERO_NULL, /* connect_it */
169 ZERO_NULL, /* connecting */
170 ZERO_NULL, /* doing */
171 ZERO_NULL, /* proto_getsock */
172 ZERO_NULL, /* doing_getsock */
173 ZERO_NULL, /* perform_getsock */
174 ZERO_NULL, /* disconnect */
175 PORT_IMAP, /* defport */
176 PROT_HTTP /* protocol */
182 * HTTP-proxyed IMAPS protocol handler.
185 static const struct Curl_handler Curl_handler_imaps_proxy = {
186 "IMAPS", /* scheme */
187 ZERO_NULL, /* setup_connection */
188 Curl_http, /* do_it */
189 Curl_http_done, /* done */
190 ZERO_NULL, /* do_more */
191 ZERO_NULL, /* connect_it */
192 ZERO_NULL, /* connecting */
193 ZERO_NULL, /* doing */
194 ZERO_NULL, /* proto_getsock */
195 ZERO_NULL, /* doing_getsock */
196 ZERO_NULL, /* perform_getsock */
197 ZERO_NULL, /* disconnect */
198 PORT_IMAPS, /* defport */
199 PROT_HTTP /* protocol */
204 /***********************************************************************
208 * Sends the formated string as an IMAP command to a server
210 * NOTE: we build the command in a fixed-length buffer, which sets length
211 * restrictions on the command!
213 * Designed to never block.
215 static CURLcode imapsendf(struct connectdata *conn,
216 const char *idstr, /* id to wait for at the
217 completion of this command */
218 const char *fmt, ...)
221 struct imap_conn *imapc = &conn->proto.imapc;
225 imapc->idstr = idstr; /* this is the thing */
227 res = Curl_pp_vsendf(&imapc->pp, fmt, ap);
234 static const char *getcmdid(struct connectdata *conn)
236 static const char * const ids[]= {
243 struct imap_conn *imapc = &conn->proto.imapc;
245 /* get the next id, but wrap at end of table */
246 imapc->cmdid = (int)((imapc->cmdid+1) % (sizeof(ids)/sizeof(ids[0])));
248 return ids[imapc->cmdid];
251 /* For the IMAP "protocol connect" and "doing" phases only */
252 static int imap_getsock(struct connectdata *conn,
253 curl_socket_t *socks,
256 return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks);
259 /* fucntion that checks for an imap status code at the start of the
261 static int imap_endofresp(struct pingpong *pp, int *resp)
263 char *line = pp->linestart_resp;
264 size_t len = pp->nread_resp;
265 struct imap_conn *imapc = &pp->conn->proto.imapc;
266 const char *id = imapc->idstr;
267 size_t id_len = strlen(id);
269 if(len >= id_len + 3) {
270 if(!memcmp(id, line, id_len) && (line[id_len] == ' ') ) {
271 /* end of response */
272 *resp = line[id_len+1]; /* O, N or B */
275 else if((imapc->state == IMAP_FETCH) &&
276 !memcmp("* ", line, 2) ) {
277 /* FETCH response we're interested in */
282 return FALSE; /* nothing for us */
285 /* This is the ONLY way to change IMAP state! */
286 static void state(struct connectdata *conn,
289 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
290 /* for debug purposes */
291 static const char * const names[]={
302 struct imap_conn *imapc = &conn->proto.imapc;
303 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
304 if(imapc->state != newstate)
305 infof(conn->data, "IMAP %p state change from %s to %s\n",
306 imapc, names[imapc->state], names[newstate]);
308 imapc->state = newstate;
311 static CURLcode imap_state_login(struct connectdata *conn)
314 struct FTP *imap = conn->data->state.proto.imap;
317 str = getcmdid(conn);
319 /* send USER and password */
320 result = imapsendf(conn, str, "%s LOGIN %s %s", str,
321 imap->user?imap->user:"",
322 imap->passwd?imap->passwd:"");
326 state(conn, IMAP_LOGIN);
331 /* for STARTTLS responses */
332 static CURLcode imap_state_starttls_resp(struct connectdata *conn,
336 CURLcode result = CURLE_OK;
337 struct SessionHandle *data = conn->data;
338 (void)instate; /* no use for this yet */
340 if(imapcode != 'O') {
341 failf(data, "STARTTLS denied. %c", imapcode);
342 result = CURLE_LOGIN_DENIED;
345 /* Curl_ssl_connect is BLOCKING */
346 result = Curl_ssl_connect(conn, FIRSTSOCKET);
347 if(CURLE_OK == result) {
348 conn->protocol |= PROT_IMAPS;
349 result = imap_state_login(conn);
352 state(conn, IMAP_STOP);
356 /* for LOGIN responses */
357 static CURLcode imap_state_login_resp(struct connectdata *conn,
361 CURLcode result = CURLE_OK;
362 struct SessionHandle *data = conn->data;
363 (void)instate; /* no use for this yet */
365 if(imapcode != 'O') {
366 failf(data, "Access denied. %c", imapcode);
367 result = CURLE_LOGIN_DENIED;
370 state(conn, IMAP_STOP);
374 /* for the (first line of) FETCH BODY[TEXT] response */
375 static CURLcode imap_state_fetch_resp(struct connectdata *conn,
379 CURLcode result = CURLE_OK;
380 struct SessionHandle *data = conn->data;
381 struct imap_conn *imapc = &conn->proto.imapc;
382 struct FTP *imap = data->state.proto.imap;
383 struct pingpong *pp = &imapc->pp;
384 const char *ptr = data->state.buffer;
385 (void)instate; /* no use for this yet */
387 if('*' != imapcode) {
388 Curl_pgrsSetDownloadSize(data, 0);
389 state(conn, IMAP_STOP);
393 /* Something like this comes "* 1 FETCH (BODY[TEXT] {2021}\r" */
394 while(*ptr && (*ptr != '{'))
398 curl_off_t filesize = curlx_strtoofft(ptr+1, NULL, 10);
400 Curl_pgrsSetDownloadSize(data, filesize);
402 infof(data, "Found %" FORMAT_OFF_TU " bytes to download\n", filesize);
405 /* At this point there is a bunch of data in the header "cache" that is
406 actually body content, send it as body and then skip it. Do note
407 that there may even be additional "headers" after the body. */
408 size_t chunk = pp->cache_size;
410 if(chunk > (size_t)filesize)
411 /* the conversion from curl_off_t to size_t is always fine here */
412 chunk = (size_t)filesize;
414 result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
420 /* we've now used parts of or the entire cache */
421 if(pp->cache_size > chunk) {
422 /* part of, move the trailing data to the start and reduce the size */
423 memmove(pp->cache, pp->cache+chunk,
424 pp->cache_size - chunk);
425 pp->cache_size -= chunk;
428 /* cache is drained */
435 infof(data, "Filesize left: %" FORMAT_OFF_T "\n", filesize);
438 /* the entire data is already transfered! */
439 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
442 Curl_setup_transfer(conn, FIRSTSOCKET, filesize, FALSE,
443 imap->bytecountp, -1, NULL); /* no upload here */
445 data->req.maxdownload = filesize;
448 /* We don't know how to parse this line */
449 result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */
451 state(conn, IMAP_STOP);
455 /* start the DO phase */
456 static CURLcode imap_select(struct connectdata *conn)
458 CURLcode result = CURLE_OK;
459 struct imap_conn *imapc = &conn->proto.imapc;
462 str = getcmdid(conn);
464 result = imapsendf(conn, str, "%s SELECT %s", str,
465 imapc->mailbox?imapc->mailbox:"");
469 state(conn, IMAP_SELECT);
473 static CURLcode imap_fetch(struct connectdata *conn)
475 CURLcode result = CURLE_OK;
478 str = getcmdid(conn);
480 /* TODO: make this select the correct mail
481 * Use "1 body[text]" to get the full mail body of mail 1
483 result = imapsendf(conn, str, "%s FETCH 1 BODY[TEXT]", str);
488 * When issued, the server will respond with a single line similar to
489 * '* 1 FETCH (BODY[TEXT] {2021}'
491 * Identifying the fetch and how many bytes of contents we can expect. We
492 * must extract that number before continuing to "download as usual".
495 state(conn, IMAP_FETCH);
499 /* for SELECT responses */
500 static CURLcode imap_state_select_resp(struct connectdata *conn,
504 CURLcode result = CURLE_OK;
505 struct SessionHandle *data = conn->data;
506 (void)instate; /* no use for this yet */
508 if(imapcode != 'O') {
509 failf(data, "Select failed");
510 result = CURLE_LOGIN_DENIED;
513 result = imap_fetch(conn);
517 static CURLcode imap_statemach_act(struct connectdata *conn)
520 curl_socket_t sock = conn->sock[FIRSTSOCKET];
521 struct SessionHandle *data=conn->data;
523 struct imap_conn *imapc = &conn->proto.imapc;
524 struct pingpong *pp = &imapc->pp;
528 return Curl_pp_flushsend(pp);
530 /* we read a piece of response */
531 result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
536 /* we have now received a full IMAP server response */
537 switch(imapc->state) {
538 case IMAP_SERVERGREET:
539 if(imapcode != 'O') {
540 failf(data, "Got unexpected imap-server response");
541 return CURLE_FTP_WEIRD_SERVER_REPLY;
544 if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
545 /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
546 to TLS connection now */
549 str = getcmdid(conn);
550 result = imapsendf(conn, str, "%s STARTTLS", str);
551 state(conn, IMAP_STARTTLS);
554 result = imap_state_login(conn);
560 result = imap_state_login_resp(conn, imapcode, imapc->state);
564 result = imap_state_starttls_resp(conn, imapcode, imapc->state);
568 result = imap_state_fetch_resp(conn, imapcode, imapc->state);
572 result = imap_state_select_resp(conn, imapcode, imapc->state);
576 /* fallthrough, just stop! */
579 state(conn, IMAP_STOP);
586 /* called repeatedly until done from multi.c */
587 static CURLcode imap_multi_statemach(struct connectdata *conn,
590 struct imap_conn *imapc = &conn->proto.imapc;
591 CURLcode result = Curl_pp_multi_statemach(&imapc->pp);
593 *done = (bool)(imapc->state == IMAP_STOP);
598 static CURLcode imap_easy_statemach(struct connectdata *conn)
600 struct imap_conn *imapc = &conn->proto.imapc;
601 struct pingpong *pp = &imapc->pp;
602 CURLcode result = CURLE_OK;
604 while(imapc->state != IMAP_STOP) {
605 result = Curl_pp_easy_statemach(pp);
614 * Allocate and initialize the struct IMAP for the current SessionHandle. If
617 static CURLcode imap_init(struct connectdata *conn)
619 struct SessionHandle *data = conn->data;
620 struct FTP *imap = data->state.proto.imap;
622 imap = data->state.proto.imap = calloc(sizeof(struct FTP), 1);
624 return CURLE_OUT_OF_MEMORY;
627 /* get some initial data into the imap struct */
628 imap->bytecountp = &data->req.bytecount;
630 /* No need to duplicate user+password, the connectdata struct won't change
631 during a session, but we re-init them here since on subsequent inits
632 since the conn struct may have changed or been replaced.
634 imap->user = conn->user;
635 imap->passwd = conn->passwd;
641 * imap_connect() should do everything that is to be considered a part of
642 * the connection phase.
644 * The variable 'done' points to will be TRUE if the protocol-layer connect
645 * phase is done when this function returns, or FALSE is not. When called as
646 * a part of the easy interface, it will always be TRUE.
648 static CURLcode imap_connect(struct connectdata *conn,
649 bool *done) /* see description above */
652 struct imap_conn *imapc = &conn->proto.imapc;
653 struct SessionHandle *data=conn->data;
654 struct pingpong *pp = &imapc->pp;
656 *done = FALSE; /* default to not done yet */
658 /* If there already is a protocol-specific struct allocated for this
659 sessionhandle, deal with it */
660 Curl_reset_reqproto(conn);
662 result = imap_init(conn);
663 if(CURLE_OK != result)
666 /* We always support persistant connections on imap */
667 conn->bits.close = FALSE;
669 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
670 pp->statemach_act = imap_statemach_act;
671 pp->endofresp = imap_endofresp;
674 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
675 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
676 /* for IMAP over HTTP proxy */
677 struct HTTP http_proxy;
678 struct FTP *imap_save;
681 /* We want "seamless" IMAP operations through HTTP proxy tunnel */
683 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
684 * conn->proto.http; we want IMAP through HTTP and we have to change the
685 * member temporarily for connecting to the HTTP proxy. After
686 * Curl_proxyCONNECT we have to set back the member to the original struct
689 imap_save = data->state.proto.imap;
690 memset(&http_proxy, 0, sizeof(http_proxy));
691 data->state.proto.http = &http_proxy;
693 result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
694 conn->host.name, conn->remote_port);
696 data->state.proto.imap = imap_save;
698 if(CURLE_OK != result)
701 #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
703 if(conn->protocol & PROT_IMAPS) {
705 /* IMAPS is simply imap with SSL for the control channel */
706 /* now, perform the SSL initialization for this socket */
707 result = Curl_ssl_connect(conn, FIRSTSOCKET);
712 Curl_pp_init(pp); /* init generic pingpong data */
714 /* When we connect, we start in the state where we await the server greeting
716 state(conn, IMAP_SERVERGREET);
717 imapc->idstr = "*"; /* we start off waiting for a '*' response */
719 if(data->state.used_interface == Curl_if_multi)
720 result = imap_multi_statemach(conn, done);
722 result = imap_easy_statemach(conn);
730 /***********************************************************************
734 * The DONE function. This does what needs to be done after a single DO has
737 * Input argument is already checked for validity.
739 static CURLcode imap_done(struct connectdata *conn, CURLcode status,
742 struct SessionHandle *data = conn->data;
743 struct FTP *imap = data->state.proto.imap;
744 CURLcode result=CURLE_OK;
748 /* When the easy handle is removed from the multi while libcurl is still
749 * trying to resolve the host name, it seems that the imap struct is not
750 * yet initialized, but the removal action calls Curl_done() which calls
751 * this function. So we simply return success if no imap pointer is set.
756 conn->bits.close = TRUE; /* marked for closure */
757 result = status; /* use the already set error code */
760 /* clear these for next connection */
761 imap->transfer = FTPTRANSFER_BODY;
766 /***********************************************************************
770 * This is the actual DO function for IMAP. Get a file/directory according to
771 * the options previously setup.
775 CURLcode imap_perform(struct connectdata *conn,
776 bool *connected, /* connect status after PASV / PORT */
779 /* this is IMAP and no proxy */
780 CURLcode result=CURLE_OK;
782 DEBUGF(infof(conn->data, "DO phase starts\n"));
784 if(conn->data->set.opt_no_body) {
785 /* requested no body means no transfer... */
786 struct FTP *imap = conn->data->state.proto.imap;
787 imap->transfer = FTPTRANSFER_INFO;
790 *dophase_done = FALSE; /* not done yet */
792 /* start the first command in the DO phase */
793 result = imap_select(conn);
797 /* run the state-machine */
798 if(conn->data->state.used_interface == Curl_if_multi)
799 result = imap_multi_statemach(conn, dophase_done);
801 result = imap_easy_statemach(conn);
802 *dophase_done = TRUE; /* with the easy interface we are done here */
804 *connected = conn->bits.tcpconnect;
807 DEBUGF(infof(conn->data, "DO phase is complete\n"));
812 /***********************************************************************
816 * This function is registered as 'curl_do' function. It decodes the path
817 * parts etc as a wrapper to the actual DO function (imap_perform).
819 * The input argument is already checked for validity.
821 static CURLcode imap_do(struct connectdata *conn, bool *done)
823 CURLcode retcode = CURLE_OK;
825 *done = FALSE; /* default to false */
828 Since connections can be re-used between SessionHandles, this might be a
829 connection already existing but on a fresh SessionHandle struct so we must
830 make sure we have a good 'struct IMAP' to play with. For new connections,
831 the struct IMAP is allocated and setup in the imap_connect() function.
833 Curl_reset_reqproto(conn);
834 retcode = imap_init(conn);
838 retcode = imap_parse_url_path(conn);
842 retcode = imap_regular_transfer(conn, done);
847 /***********************************************************************
851 * This should be called before calling sclose(). We should then wait for the
852 * response from the server before returning. The calling code should then try
853 * to close the connection.
856 static CURLcode imap_logout(struct connectdata *conn)
858 CURLcode result = CURLE_OK;
861 str = getcmdid(conn);
863 result = imapsendf(conn, str, "%s LOGOUT", str, NULL);
866 state(conn, IMAP_LOGOUT);
868 result = imap_easy_statemach(conn);
873 /***********************************************************************
877 * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
878 * resources. BLOCKING.
880 static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
882 struct imap_conn *imapc= &conn->proto.imapc;
884 /* The IMAP session may or may not have been allocated/setup at this
886 if(!dead_connection && imapc->pp.conn)
887 (void)imap_logout(conn); /* ignore errors on the LOGOUT */
889 Curl_pp_disconnect(&imapc->pp);
891 Curl_safefree(imapc->mailbox);
896 /***********************************************************************
898 * imap_parse_url_path()
900 * Parse the URL path into separate path components.
903 static CURLcode imap_parse_url_path(struct connectdata *conn)
905 /* the imap struct is already inited in imap_connect() */
906 struct imap_conn *imapc = &conn->proto.imapc;
907 struct SessionHandle *data = conn->data;
908 const char *path = data->state.path;
914 /* url decode the path and use this mailbox */
915 imapc->mailbox = curl_easy_unescape(data, path, 0, &len);
917 return CURLE_OUT_OF_MEMORY;
922 /* call this when the DO phase has completed */
923 static CURLcode imap_dophase_done(struct connectdata *conn,
926 struct FTP *imap = conn->data->state.proto.imap;
929 if(imap->transfer != FTPTRANSFER_BODY)
930 /* no data to transfer */
931 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
936 /* called from multi.c while DOing */
937 static CURLcode imap_doing(struct connectdata *conn,
941 result = imap_multi_statemach(conn, dophase_done);
944 result = imap_dophase_done(conn, FALSE /* not connected */);
946 DEBUGF(infof(conn->data, "DO phase is complete\n"));
951 /***********************************************************************
953 * imap_regular_transfer()
955 * The input argument is already checked for validity.
957 * Performs all commands done before a regular transfer between a local and a
962 CURLcode imap_regular_transfer(struct connectdata *conn,
965 CURLcode result=CURLE_OK;
966 bool connected=FALSE;
967 struct SessionHandle *data = conn->data;
968 data->req.size = -1; /* make sure this is unknown at this point */
970 Curl_pgrsSetUploadCounter(data, 0);
971 Curl_pgrsSetDownloadCounter(data, 0);
972 Curl_pgrsSetUploadSize(data, 0);
973 Curl_pgrsSetDownloadSize(data, 0);
975 result = imap_perform(conn,
976 &connected, /* have we connected after PASV/PORT */
977 dophase_done); /* all commands in the DO-phase done? */
979 if(CURLE_OK == result) {
982 /* the DO phase has not completed yet */
985 result = imap_dophase_done(conn, connected);
993 static CURLcode imap_setup_connection(struct connectdata * conn)
995 struct SessionHandle *data = conn->data;
997 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
998 /* Unless we have asked to tunnel imap operations through the proxy, we
999 switch and use HTTP operations only */
1000 #ifndef CURL_DISABLE_HTTP
1001 if(conn->handler == &Curl_handler_imap)
1002 conn->handler = &Curl_handler_imap_proxy;
1005 conn->handler = &Curl_handler_imaps_proxy;
1007 failf(data, "IMAPS not supported!");
1008 return CURLE_UNSUPPORTED_PROTOCOL;
1012 * We explicitly mark this connection as persistent here as we're doing
1013 * IMAP over HTTP and thus we accidentally avoid setting this value
1016 conn->bits.close = FALSE;
1018 failf(data, "IMAP over http proxy requires HTTP support built-in!");
1019 return CURLE_UNSUPPORTED_PROTOCOL;
1023 data->state.path++; /* don't include the initial slash */
1028 #endif /* CURL_DISABLE_IMAP */