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
25 ***************************************************************************/
29 #ifndef CURL_DISABLE_IMAP
40 #ifdef HAVE_SYS_SOCKET_H
41 #include <sys/socket.h>
43 #ifdef HAVE_NETINET_IN_H
44 #include <netinet/in.h>
46 #ifdef HAVE_ARPA_INET_H
47 #include <arpa/inet.h>
50 #include <sys/utsname.h>
60 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
62 #define in_addr_t unsigned long
65 #include <curl/curl.h>
68 #include "easyif.h" /* for Curl_convert_... prototypes */
75 #include "http.h" /* for HTTP proxy tunnel stuff */
79 #include "strtoofft.h"
88 #include "strtoofft.h"
90 #define _MPRINTF_REPLACE /* use our functions only */
91 #include <curl/mprintf.h>
93 #include "curl_memory.h"
94 /* The last #include file should be: */
97 /* Local API functions */
98 static CURLcode imap_parse_url_path(struct connectdata *conn);
99 static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done);
100 static CURLcode imap_do(struct connectdata *conn, bool *done);
101 static CURLcode imap_done(struct connectdata *conn,
102 CURLcode, bool premature);
103 static CURLcode imap_connect(struct connectdata *conn, bool *done);
104 static CURLcode imap_disconnect(struct connectdata *conn);
105 static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
106 static int imap_getsock(struct connectdata *conn,
107 curl_socket_t *socks,
109 static CURLcode imap_doing(struct connectdata *conn,
111 static CURLcode imap_setup_connection(struct connectdata * conn);
114 * IMAP protocol handler.
117 const struct Curl_handler Curl_handler_imap = {
119 imap_setup_connection, /* setup_connection */
121 imap_done, /* done */
122 ZERO_NULL, /* do_more */
123 imap_connect, /* connect_it */
124 imap_multi_statemach, /* connecting */
125 imap_doing, /* doing */
126 imap_getsock, /* proto_getsock */
127 imap_getsock, /* doing_getsock */
128 ZERO_NULL, /* perform_getsock */
129 imap_disconnect, /* disconnect */
130 PORT_IMAP, /* defport */
131 PROT_IMAP /* protocol */
137 * IMAPS protocol handler.
140 const struct Curl_handler Curl_handler_imaps = {
141 "IMAPS", /* scheme */
142 imap_setup_connection, /* setup_connection */
144 imap_done, /* done */
145 ZERO_NULL, /* do_more */
146 imap_connect, /* connect_it */
147 imap_multi_statemach, /* connecting */
148 imap_doing, /* doing */
149 imap_getsock, /* proto_getsock */
150 imap_getsock, /* doing_getsock */
151 ZERO_NULL, /* perform_getsock */
152 imap_disconnect, /* disconnect */
153 PORT_IMAPS, /* defport */
154 PROT_IMAP | PROT_IMAPS | PROT_SSL /* protocol */
158 #ifndef CURL_DISABLE_HTTP
160 * HTTP-proxyed IMAP protocol handler.
163 static const struct Curl_handler Curl_handler_imap_proxy = {
165 ZERO_NULL, /* setup_connection */
166 Curl_http, /* do_it */
167 Curl_http_done, /* done */
168 ZERO_NULL, /* do_more */
169 ZERO_NULL, /* connect_it */
170 ZERO_NULL, /* connecting */
171 ZERO_NULL, /* doing */
172 ZERO_NULL, /* proto_getsock */
173 ZERO_NULL, /* doing_getsock */
174 ZERO_NULL, /* perform_getsock */
175 ZERO_NULL, /* disconnect */
176 PORT_IMAP, /* defport */
177 PROT_HTTP /* protocol */
183 * HTTP-proxyed IMAPS protocol handler.
186 static const struct Curl_handler Curl_handler_imaps_proxy = {
187 "IMAPS", /* scheme */
188 ZERO_NULL, /* setup_connection */
189 Curl_http, /* do_it */
190 Curl_http_done, /* done */
191 ZERO_NULL, /* do_more */
192 ZERO_NULL, /* connect_it */
193 ZERO_NULL, /* connecting */
194 ZERO_NULL, /* doing */
195 ZERO_NULL, /* proto_getsock */
196 ZERO_NULL, /* doing_getsock */
197 ZERO_NULL, /* perform_getsock */
198 ZERO_NULL, /* disconnect */
199 PORT_IMAPS, /* defport */
200 PROT_HTTP /* protocol */
205 /***********************************************************************
209 * Sends the formated string as an IMAP command to a server
211 * NOTE: we build the command in a fixed-length buffer, which sets length
212 * restrictions on the command!
214 * Designed to never block.
216 static CURLcode imapsendf(struct connectdata *conn,
217 const char *idstr, /* id to wait for at the
218 completion of this command */
219 const char *fmt, ...)
222 struct imap_conn *imapc = &conn->proto.imapc;
226 imapc->idstr = idstr; /* this is the thing */
228 res = Curl_pp_vsendf(&imapc->pp, fmt, ap);
235 static const char *getcmdid(struct connectdata *conn)
237 static const char * const ids[]= {
244 struct imap_conn *imapc = &conn->proto.imapc;
246 /* get the next id, but wrap at end of table */
247 imapc->cmdid = (imapc->cmdid+1)% (sizeof(ids)/sizeof(ids[0]));
249 return ids[imapc->cmdid];
252 /* For the IMAP "protocol connect" and "doing" phases only */
253 static int imap_getsock(struct connectdata *conn,
254 curl_socket_t *socks,
257 return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks);
260 /* fucntion that checks for an imap status code at the start of the
262 static int imap_endofresp(struct pingpong *pp, int *resp)
264 char *line = pp->linestart_resp;
265 size_t len = pp->nread_resp;
266 struct imap_conn *imapc = &pp->conn->proto.imapc;
267 const char *id = imapc->idstr;
268 size_t id_len = strlen(id);
270 if(len >= id_len + 3) {
271 if(!memcmp(id, line, id_len) && (line[id_len] == ' ') ) {
272 /* end of response */
273 *resp = line[id_len+1]; /* O, N or B */
276 else if((imapc->state == IMAP_FETCH) &&
277 !memcmp("* ", line, 2) ) {
278 /* FETCH response we're interested in */
283 return FALSE; /* nothing for us */
286 /* This is the ONLY way to change IMAP state! */
287 static void state(struct connectdata *conn,
290 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
291 /* for debug purposes */
292 static const char * const names[]={
303 struct imap_conn *imapc = &conn->proto.imapc;
304 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
305 if(imapc->state != newstate)
306 infof(conn->data, "IMAP %p state change from %s to %s\n",
307 imapc, names[imapc->state], names[newstate]);
309 imapc->state = newstate;
312 static CURLcode imap_state_login(struct connectdata *conn)
315 struct FTP *imap = conn->data->state.proto.imap;
318 str = getcmdid(conn);
320 /* send USER and password */
321 result = imapsendf(conn, str, "%s LOGIN %s %s", str,
322 imap->user?imap->user:"",
323 imap->passwd?imap->passwd:"");
327 state(conn, IMAP_LOGIN);
332 /* for STARTTLS responses */
333 static CURLcode imap_state_starttls_resp(struct connectdata *conn,
337 CURLcode result = CURLE_OK;
338 struct SessionHandle *data = conn->data;
339 (void)instate; /* no use for this yet */
341 if(imapcode != 'O') {
342 failf(data, "STARTTLS denied. %c", imapcode);
343 result = CURLE_LOGIN_DENIED;
346 /* Curl_ssl_connect is BLOCKING */
347 result = Curl_ssl_connect(conn, FIRSTSOCKET);
348 if(CURLE_OK == result) {
349 conn->protocol |= PROT_IMAPS;
350 result = imap_state_login(conn);
353 state(conn, IMAP_STOP);
357 /* for LOGIN responses */
358 static CURLcode imap_state_login_resp(struct connectdata *conn,
362 CURLcode result = CURLE_OK;
363 struct SessionHandle *data = conn->data;
364 (void)instate; /* no use for this yet */
366 if(imapcode != 'O') {
367 failf(data, "Access denied. %c", imapcode);
368 result = CURLE_LOGIN_DENIED;
371 state(conn, IMAP_STOP);
375 /* for the (first line of) FETCH BODY[TEXT] response */
376 static CURLcode imap_state_fetch_resp(struct connectdata *conn,
380 CURLcode result = CURLE_OK;
381 struct SessionHandle *data = conn->data;
382 struct imap_conn *imapc = &conn->proto.imapc;
383 struct FTP *imap = data->state.proto.imap;
384 struct pingpong *pp = &imapc->pp;
385 const char *ptr = data->state.buffer;
386 (void)instate; /* no use for this yet */
388 if('*' != imapcode) {
389 Curl_pgrsSetDownloadSize(data, 0);
390 state(conn, IMAP_STOP);
394 /* Something like this comes "* 1 FETCH (BODY[TEXT] {2021}\r" */
395 while(*ptr && (*ptr != '{'))
399 curl_off_t filesize = curlx_strtoofft(ptr+1, NULL, 10);
401 Curl_pgrsSetDownloadSize(data, filesize);
403 infof(data, "Found %" FORMAT_OFF_TU " bytes to download\n", filesize);
406 /* At this point there is a bunch of data in the header "cache" that is
407 actually body content, send it as body and then skip it. Do note
408 that there may even be additional "headers" after the body. */
409 size_t chunk = pp->cache_size;
411 if(chunk > (size_t)filesize)
412 /* the conversion from curl_off_t to size_t is always fine here */
413 chunk = (size_t)filesize;
415 result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
421 /* we've now used parts of or the entire cache */
422 if(pp->cache_size > chunk) {
423 /* part of, move the trailing data to the start and reduce the size */
424 memmove(pp->cache, pp->cache+chunk,
425 pp->cache_size - chunk);
426 pp->cache_size -= chunk;
429 /* cache is drained */
436 infof(data, "Filesize left: %" FORMAT_OFF_T "\n", filesize);
439 /* the entire data is already transfered! */
440 result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
443 result=Curl_setup_transfer(conn, FIRSTSOCKET, filesize, FALSE,
445 -1, NULL); /* no upload here */
447 data->req.maxdownload = filesize;
450 /* We don't know how to parse this line */
451 result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */
453 state(conn, IMAP_STOP);
457 /* start the DO phase */
458 static CURLcode imap_select(struct connectdata *conn)
460 CURLcode result = CURLE_OK;
461 struct imap_conn *imapc = &conn->proto.imapc;
464 str = getcmdid(conn);
466 result = imapsendf(conn, str, "%s SELECT %s", str,
467 imapc->mailbox?imapc->mailbox:"");
471 state(conn, IMAP_SELECT);
475 static CURLcode imap_fetch(struct connectdata *conn)
477 CURLcode result = CURLE_OK;
480 str = getcmdid(conn);
482 /* TODO: make this select the correct mail
483 * Use "1 body[text]" to get the full mail body of mail 1
485 result = imapsendf(conn, str, "%s FETCH 1 BODY[TEXT]", str);
490 * When issued, the server will respond with a single line similar to
491 * '* 1 FETCH (BODY[TEXT] {2021}'
493 * Identifying the fetch and how many bytes of contents we can expect. We
494 * must extract that number before continuing to "download as usual".
497 state(conn, IMAP_FETCH);
501 /* for SELECT responses */
502 static CURLcode imap_state_select_resp(struct connectdata *conn,
506 CURLcode result = CURLE_OK;
507 struct SessionHandle *data = conn->data;
508 (void)instate; /* no use for this yet */
510 if(imapcode != 'O') {
511 failf(data, "Select failed");
512 result = CURLE_LOGIN_DENIED;
515 result = imap_fetch(conn);
519 static CURLcode imap_statemach_act(struct connectdata *conn)
522 curl_socket_t sock = conn->sock[FIRSTSOCKET];
523 struct SessionHandle *data=conn->data;
525 struct imap_conn *imapc = &conn->proto.imapc;
526 struct pingpong *pp = &imapc->pp;
530 return Curl_pp_flushsend(pp);
532 /* we read a piece of response */
533 result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
538 /* we have now received a full IMAP server response */
539 switch(imapc->state) {
540 case IMAP_SERVERGREET:
541 if(imapcode != 'O') {
542 failf(data, "Got unexpected imap-server response");
543 return CURLE_FTP_WEIRD_SERVER_REPLY;
546 if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
547 /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
548 to TLS connection now */
551 str = getcmdid(conn);
552 result = imapsendf(conn, str, "%s STARTTLS", str);
553 state(conn, IMAP_STARTTLS);
556 result = imap_state_login(conn);
562 result = imap_state_login_resp(conn, imapcode, imapc->state);
566 result = imap_state_starttls_resp(conn, imapcode, imapc->state);
570 result = imap_state_fetch_resp(conn, imapcode, imapc->state);
574 result = imap_state_select_resp(conn, imapcode, imapc->state);
578 /* fallthrough, just stop! */
581 state(conn, IMAP_STOP);
588 /* called repeatedly until done from multi.c */
589 static CURLcode imap_multi_statemach(struct connectdata *conn,
592 struct imap_conn *imapc = &conn->proto.imapc;
593 CURLcode result = Curl_pp_multi_statemach(&imapc->pp);
595 *done = (bool)(imapc->state == IMAP_STOP);
600 static CURLcode imap_easy_statemach(struct connectdata *conn)
602 struct imap_conn *imapc = &conn->proto.imapc;
603 struct pingpong *pp = &imapc->pp;
604 CURLcode result = CURLE_OK;
606 while(imapc->state != IMAP_STOP) {
607 result = Curl_pp_easy_statemach(pp);
616 * Allocate and initialize the struct IMAP for the current SessionHandle. If
619 static CURLcode imap_init(struct connectdata *conn)
621 struct SessionHandle *data = conn->data;
622 struct FTP *imap = data->state.proto.imap;
624 imap = data->state.proto.imap = calloc(sizeof(struct FTP), 1);
626 return CURLE_OUT_OF_MEMORY;
629 /* get some initial data into the imap struct */
630 imap->bytecountp = &data->req.bytecount;
632 /* No need to duplicate user+password, the connectdata struct won't change
633 during a session, but we re-init them here since on subsequent inits
634 since the conn struct may have changed or been replaced.
636 imap->user = conn->user;
637 imap->passwd = conn->passwd;
643 * imap_connect() should do everything that is to be considered a part of
644 * the connection phase.
646 * The variable 'done' points to will be TRUE if the protocol-layer connect
647 * phase is done when this function returns, or FALSE is not. When called as
648 * a part of the easy interface, it will always be TRUE.
650 static CURLcode imap_connect(struct connectdata *conn,
651 bool *done) /* see description above */
654 struct imap_conn *imapc = &conn->proto.imapc;
655 struct SessionHandle *data=conn->data;
656 struct pingpong *pp = &imapc->pp;
658 *done = FALSE; /* default to not done yet */
660 /* If there already is a protocol-specific struct allocated for this
661 sessionhandle, deal with it */
662 Curl_reset_reqproto(conn);
664 result = imap_init(conn);
665 if(CURLE_OK != result)
668 /* We always support persistant connections on imap */
669 conn->bits.close = FALSE;
671 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
672 pp->statemach_act = imap_statemach_act;
673 pp->endofresp = imap_endofresp;
676 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
677 if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
678 /* for IMAP over HTTP proxy */
679 struct HTTP http_proxy;
680 struct FTP *imap_save;
683 /* We want "seamless" IMAP operations through HTTP proxy tunnel */
685 /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
686 * conn->proto.http; we want IMAP through HTTP and we have to change the
687 * member temporarily for connecting to the HTTP proxy. After
688 * Curl_proxyCONNECT we have to set back the member to the original struct
691 imap_save = data->state.proto.imap;
692 memset(&http_proxy, 0, sizeof(http_proxy));
693 data->state.proto.http = &http_proxy;
695 result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
696 conn->host.name, conn->remote_port);
698 data->state.proto.imap = imap_save;
700 if(CURLE_OK != result)
703 #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
705 if(conn->protocol & PROT_IMAPS) {
707 /* IMAPS is simply imap with SSL for the control channel */
708 /* now, perform the SSL initialization for this socket */
709 result = Curl_ssl_connect(conn, FIRSTSOCKET);
714 Curl_pp_init(pp); /* init generic pingpong data */
716 /* When we connect, we start in the state where we await the server greeting
718 state(conn, IMAP_SERVERGREET);
719 imapc->idstr = "*"; /* we start off waiting for a '*' response */
721 if(data->state.used_interface == Curl_if_multi)
722 result = imap_multi_statemach(conn, done);
724 result = imap_easy_statemach(conn);
732 /***********************************************************************
736 * The DONE function. This does what needs to be done after a single DO has
739 * Input argument is already checked for validity.
741 static CURLcode imap_done(struct connectdata *conn, CURLcode status,
744 struct SessionHandle *data = conn->data;
745 struct FTP *imap = data->state.proto.imap;
746 CURLcode result=CURLE_OK;
750 /* When the easy handle is removed from the multi while libcurl is still
751 * trying to resolve the host name, it seems that the imap struct is not
752 * yet initialized, but the removal action calls Curl_done() which calls
753 * this function. So we simply return success if no imap pointer is set.
758 conn->bits.close = TRUE; /* marked for closure */
759 result = status; /* use the already set error code */
762 /* clear these for next connection */
763 imap->transfer = FTPTRANSFER_BODY;
768 /***********************************************************************
772 * This is the actual DO function for IMAP. Get a file/directory according to
773 * the options previously setup.
777 CURLcode imap_perform(struct connectdata *conn,
778 bool *connected, /* connect status after PASV / PORT */
781 /* this is IMAP and no proxy */
782 CURLcode result=CURLE_OK;
784 DEBUGF(infof(conn->data, "DO phase starts\n"));
786 if(conn->data->set.opt_no_body) {
787 /* requested no body means no transfer... */
788 struct FTP *imap = conn->data->state.proto.imap;
789 imap->transfer = FTPTRANSFER_INFO;
792 *dophase_done = FALSE; /* not done yet */
794 /* start the first command in the DO phase */
795 result = imap_select(conn);
799 /* run the state-machine */
800 if(conn->data->state.used_interface == Curl_if_multi)
801 result = imap_multi_statemach(conn, dophase_done);
803 result = imap_easy_statemach(conn);
804 *dophase_done = TRUE; /* with the easy interface we are done here */
806 *connected = conn->bits.tcpconnect;
809 DEBUGF(infof(conn->data, "DO phase is complete\n"));
814 /***********************************************************************
818 * This function is registered as 'curl_do' function. It decodes the path
819 * parts etc as a wrapper to the actual DO function (imap_perform).
821 * The input argument is already checked for validity.
823 static CURLcode imap_do(struct connectdata *conn, bool *done)
825 CURLcode retcode = CURLE_OK;
827 *done = FALSE; /* default to false */
830 Since connections can be re-used between SessionHandles, this might be a
831 connection already existing but on a fresh SessionHandle struct so we must
832 make sure we have a good 'struct IMAP' to play with. For new connections,
833 the struct IMAP is allocated and setup in the imap_connect() function.
835 Curl_reset_reqproto(conn);
836 retcode = imap_init(conn);
840 retcode = imap_parse_url_path(conn);
844 retcode = imap_regular_transfer(conn, done);
849 /***********************************************************************
853 * This should be called before calling sclose(). We should then wait for the
854 * response from the server before returning. The calling code should then try
855 * to close the connection.
858 static CURLcode imap_logout(struct connectdata *conn)
860 CURLcode result = CURLE_OK;
863 str = getcmdid(conn);
865 result = imapsendf(conn, str, "%s LOGOUT", str, NULL);
868 state(conn, IMAP_LOGOUT);
870 result = imap_easy_statemach(conn);
875 /***********************************************************************
879 * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
880 * resources. BLOCKING.
882 static CURLcode imap_disconnect(struct connectdata *conn)
884 struct imap_conn *imapc= &conn->proto.imapc;
886 /* The IMAP session may or may not have been allocated/setup at this
889 (void)imap_logout(conn); /* ignore errors on the LOGOUT */
891 Curl_pp_disconnect(&imapc->pp);
893 Curl_safefree(imapc->mailbox);
898 /***********************************************************************
900 * imap_parse_url_path()
902 * Parse the URL path into separate path components.
905 static CURLcode imap_parse_url_path(struct connectdata *conn)
907 /* the imap struct is already inited in imap_connect() */
908 struct imap_conn *imapc = &conn->proto.imapc;
909 struct SessionHandle *data = conn->data;
910 const char *path = data->state.path;
916 /* url decode the path and use this mailbox */
917 imapc->mailbox = curl_easy_unescape(data, path, 0, &len);
919 return CURLE_OUT_OF_MEMORY;
924 /* call this when the DO phase has completed */
925 static CURLcode imap_dophase_done(struct connectdata *conn,
928 CURLcode result = CURLE_OK;
929 struct FTP *imap = conn->data->state.proto.imap;
932 if(imap->transfer != FTPTRANSFER_BODY)
933 /* no data to transfer */
934 result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
939 /* called from multi.c while DOing */
940 static CURLcode imap_doing(struct connectdata *conn,
944 result = imap_multi_statemach(conn, dophase_done);
947 result = imap_dophase_done(conn, FALSE /* not connected */);
949 DEBUGF(infof(conn->data, "DO phase is complete\n"));
954 /***********************************************************************
956 * imap_regular_transfer()
958 * The input argument is already checked for validity.
960 * Performs all commands done before a regular transfer between a local and a
965 CURLcode imap_regular_transfer(struct connectdata *conn,
968 CURLcode result=CURLE_OK;
969 bool connected=FALSE;
970 struct SessionHandle *data = conn->data;
971 data->req.size = -1; /* make sure this is unknown at this point */
973 Curl_pgrsSetUploadCounter(data, 0);
974 Curl_pgrsSetDownloadCounter(data, 0);
975 Curl_pgrsSetUploadSize(data, 0);
976 Curl_pgrsSetDownloadSize(data, 0);
978 result = imap_perform(conn,
979 &connected, /* have we connected after PASV/PORT */
980 dophase_done); /* all commands in the DO-phase done? */
982 if(CURLE_OK == result) {
985 /* the DO phase has not completed yet */
988 result = imap_dophase_done(conn, connected);
996 static CURLcode imap_setup_connection(struct connectdata * conn)
998 struct SessionHandle *data = conn->data;
1000 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1001 /* Unless we have asked to tunnel imap operations through the proxy, we
1002 switch and use HTTP operations only */
1003 #ifndef CURL_DISABLE_HTTP
1004 if(conn->handler == &Curl_handler_imap)
1005 conn->handler = &Curl_handler_imap_proxy;
1008 conn->handler = &Curl_handler_imaps_proxy;
1010 failf(data, "IMAPS not supported!");
1011 return CURLE_UNSUPPORTED_PROTOCOL;
1015 * We explicitly mark this connection as persistent here as we're doing
1016 * IMAP over HTTP and thus we accidentally avoid setting this value
1019 conn->bits.close = FALSE;
1021 failf(data, "IMAP over http proxy requires HTTP support built-in!");
1022 return CURLE_UNSUPPORTED_PROTOCOL;
1026 data->state.path++; /* don't include the initial slash */
1031 #endif /* CURL_DISABLE_IMAP */