1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2012, 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 ***************************************************************************/
26 #include "curl_setup.h"
28 #ifndef CURL_DISABLE_IMAP
30 #ifdef HAVE_NETINET_IN_H
31 #include <netinet/in.h>
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
37 #include <sys/utsname.h>
47 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
49 #define in_addr_t unsigned long
52 #include <curl/curl.h>
53 #include "curl_urldata.h"
54 #include "curl_sendf.h"
55 #include "curl_if2ip.h"
56 #include "curl_hostip.h"
57 #include "curl_progress.h"
58 #include "curl_transfer.h"
59 #include "curl_escape.h"
60 #include "curl_http.h" /* for HTTP proxy tunnel stuff */
61 #include "curl_socks.h"
62 #include "curl_imap.h"
64 #include "curl_strtoofft.h"
65 #include "curl_strequal.h"
66 #include "curl_sslgen.h"
67 #include "curl_connect.h"
68 #include "curl_strerror.h"
69 #include "curl_select.h"
70 #include "curl_multiif.h"
72 #include "curl_rawstr.h"
74 #define _MPRINTF_REPLACE /* use our functions only */
75 #include <curl/mprintf.h>
77 #include "curl_memory.h"
78 /* The last #include file should be: */
79 #include "curl_memdebug.h"
81 /* Local API functions */
82 static CURLcode imap_parse_url_path(struct connectdata *conn);
83 static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done);
84 static CURLcode imap_do(struct connectdata *conn, bool *done);
85 static CURLcode imap_done(struct connectdata *conn,
86 CURLcode, bool premature);
87 static CURLcode imap_connect(struct connectdata *conn, bool *done);
88 static CURLcode imap_disconnect(struct connectdata *conn, bool dead);
89 static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
90 static int imap_getsock(struct connectdata *conn,
93 static CURLcode imap_doing(struct connectdata *conn,
95 static CURLcode imap_setup_connection(struct connectdata * conn);
96 static CURLcode imap_state_upgrade_tls(struct connectdata *conn);
99 * IMAP protocol handler.
102 const struct Curl_handler Curl_handler_imap = {
104 imap_setup_connection, /* setup_connection */
106 imap_done, /* done */
107 ZERO_NULL, /* do_more */
108 imap_connect, /* connect_it */
109 imap_multi_statemach, /* connecting */
110 imap_doing, /* doing */
111 imap_getsock, /* proto_getsock */
112 imap_getsock, /* doing_getsock */
113 ZERO_NULL, /* domore_getsock */
114 ZERO_NULL, /* perform_getsock */
115 imap_disconnect, /* disconnect */
116 ZERO_NULL, /* readwrite */
117 PORT_IMAP, /* defport */
118 CURLPROTO_IMAP, /* protocol */
119 PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
120 | PROTOPT_NOURLQUERY /* flags */
126 * IMAPS protocol handler.
129 const struct Curl_handler Curl_handler_imaps = {
130 "IMAPS", /* scheme */
131 imap_setup_connection, /* setup_connection */
133 imap_done, /* done */
134 ZERO_NULL, /* do_more */
135 imap_connect, /* connect_it */
136 imap_multi_statemach, /* connecting */
137 imap_doing, /* doing */
138 imap_getsock, /* proto_getsock */
139 imap_getsock, /* doing_getsock */
140 ZERO_NULL, /* domore_getsock */
141 ZERO_NULL, /* perform_getsock */
142 imap_disconnect, /* disconnect */
143 ZERO_NULL, /* readwrite */
144 PORT_IMAPS, /* defport */
145 CURLPROTO_IMAP | CURLPROTO_IMAPS, /* protocol */
146 PROTOPT_CLOSEACTION | PROTOPT_SSL | PROTOPT_NEEDSPWD
147 | PROTOPT_NOURLQUERY /* flags */
151 #ifndef CURL_DISABLE_HTTP
153 * HTTP-proxyed IMAP protocol handler.
156 static const struct Curl_handler Curl_handler_imap_proxy = {
158 ZERO_NULL, /* setup_connection */
159 Curl_http, /* do_it */
160 Curl_http_done, /* done */
161 ZERO_NULL, /* do_more */
162 ZERO_NULL, /* connect_it */
163 ZERO_NULL, /* connecting */
164 ZERO_NULL, /* doing */
165 ZERO_NULL, /* proto_getsock */
166 ZERO_NULL, /* doing_getsock */
167 ZERO_NULL, /* domore_getsock */
168 ZERO_NULL, /* perform_getsock */
169 ZERO_NULL, /* disconnect */
170 ZERO_NULL, /* readwrite */
171 PORT_IMAP, /* defport */
172 CURLPROTO_HTTP, /* protocol */
173 PROTOPT_NONE /* flags */
179 * HTTP-proxyed IMAPS protocol handler.
182 static const struct Curl_handler Curl_handler_imaps_proxy = {
183 "IMAPS", /* scheme */
184 ZERO_NULL, /* setup_connection */
185 Curl_http, /* do_it */
186 Curl_http_done, /* done */
187 ZERO_NULL, /* do_more */
188 ZERO_NULL, /* connect_it */
189 ZERO_NULL, /* connecting */
190 ZERO_NULL, /* doing */
191 ZERO_NULL, /* proto_getsock */
192 ZERO_NULL, /* doing_getsock */
193 ZERO_NULL, /* domore_getsock */
194 ZERO_NULL, /* perform_getsock */
195 ZERO_NULL, /* disconnect */
196 ZERO_NULL, /* readwrite */
197 PORT_IMAPS, /* defport */
198 CURLPROTO_HTTP, /* protocol */
199 PROTOPT_NONE /* flags */
204 /***********************************************************************
208 * Sends the formated string as an IMAP command to a server
210 * Designed to never block.
212 static CURLcode imapsendf(struct connectdata *conn,
213 const char *idstr, /* id to wait for at the
214 completion of this command */
215 const char *fmt, ...)
218 struct imap_conn *imapc = &conn->proto.imapc;
222 imapc->idstr = idstr; /* this is the thing */
224 res = Curl_pp_vsendf(&imapc->pp, fmt, ap);
231 static const char *getcmdid(struct connectdata *conn)
233 static const char * const ids[]= {
240 struct imap_conn *imapc = &conn->proto.imapc;
242 /* get the next id, but wrap at end of table */
243 imapc->cmdid = (int)((imapc->cmdid+1) % (sizeof(ids)/sizeof(ids[0])));
245 return ids[imapc->cmdid];
248 /***********************************************************************
252 * Checks the input string for characters that need escaping and returns an
253 * atom ready for sending to the server.
255 * The returned string needs to be freed.
258 static char* imap_atom(const char* str)
262 size_t backsp_count = 0;
263 size_t quote_count = 0;
264 bool space_exists = FALSE;
271 /* Count any unescapped characters */
284 /* Does the input contain any unescapped characters? */
285 if(!backsp_count && !quote_count && !space_exists)
288 /* Calculate the new string length */
289 newlen = strlen(str) + backsp_count + quote_count + (space_exists ? 2 : 0);
291 /* Allocate the new string */
292 newstr = (char *) malloc((newlen + 1) * sizeof(char));
296 /* Surround the string in quotes if necessary */
300 newstr[newlen - 1] = '"';
304 /* Copy the string, escaping backslash and quote characters along the way */
307 if(*p1 == '\\' || *p1 == '"') {
318 /* Terminate the string */
319 newstr[newlen] = '\0';
324 /* For the IMAP "protocol connect" and "doing" phases only */
325 static int imap_getsock(struct connectdata *conn,
326 curl_socket_t *socks,
329 return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks);
332 /* function that checks for an imap status code at the start of the
334 static int imap_endofresp(struct pingpong *pp, int *resp)
336 char *line = pp->linestart_resp;
337 size_t len = pp->nread_resp;
338 struct imap_conn *imapc = &pp->conn->proto.imapc;
339 const char *id = imapc->idstr;
340 size_t id_len = strlen(id);
342 if(len >= id_len + 3) {
343 if(!memcmp(id, line, id_len) && (line[id_len] == ' ') ) {
344 /* end of response */
345 *resp = line[id_len+1]; /* O, N or B */
348 else if((imapc->state == IMAP_FETCH) &&
349 !memcmp("* ", line, 2) ) {
350 /* FETCH response we're interested in */
355 return FALSE; /* nothing for us */
358 /* This is the ONLY way to change IMAP state! */
359 static void state(struct connectdata *conn,
362 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
363 /* for debug purposes */
364 static const char * const names[]={
376 struct imap_conn *imapc = &conn->proto.imapc;
377 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
378 if(imapc->state != newstate)
379 infof(conn->data, "IMAP %p state change from %s to %s\n",
380 imapc, names[imapc->state], names[newstate]);
382 imapc->state = newstate;
385 static CURLcode imap_state_login(struct connectdata *conn)
388 struct FTP *imap = conn->data->state.proto.imap;
389 const char *str = getcmdid(conn);
390 char *user = imap_atom(imap->user);
391 char *passwd = imap_atom(imap->passwd);
393 /* send USER and password */
394 result = imapsendf(conn, str, "%s LOGIN %s %s", str,
395 user ? user : "", passwd ? passwd : "");
398 Curl_safefree(passwd);
403 state(conn, IMAP_LOGIN);
409 static void imap_to_imaps(struct connectdata *conn)
411 conn->handler = &Curl_handler_imaps;
414 #define imap_to_imaps(x) Curl_nop_stmt
417 /* for the initial server greeting */
418 static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
422 CURLcode result = CURLE_OK;
423 struct SessionHandle *data = conn->data;
425 (void)instate; /* no use for this yet */
427 if(imapcode != 'O') {
428 failf(data, "Got unexpected imap-server response");
429 return CURLE_FTP_WEIRD_SERVER_REPLY;
432 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
433 /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
434 to TLS connection now */
437 str = getcmdid(conn);
438 result = imapsendf(conn, str, "%s STARTTLS", str);
439 state(conn, IMAP_STARTTLS);
442 result = imap_state_login(conn);
447 /* for STARTTLS responses */
448 static CURLcode imap_state_starttls_resp(struct connectdata *conn,
452 CURLcode result = CURLE_OK;
453 struct SessionHandle *data = conn->data;
454 (void)instate; /* no use for this yet */
456 if(imapcode != 'O') {
457 if(data->set.use_ssl != CURLUSESSL_TRY) {
458 failf(data, "STARTTLS denied. %c", imapcode);
459 result = CURLE_USE_SSL_FAILED;
462 result = imap_state_login(conn);
465 if(data->state.used_interface == Curl_if_multi) {
466 state(conn, IMAP_UPGRADETLS);
467 return imap_state_upgrade_tls(conn);
470 result = Curl_ssl_connect(conn, FIRSTSOCKET);
471 if(CURLE_OK == result) {
473 result = imap_state_login(conn);
478 state(conn, IMAP_STOP);
483 static CURLcode imap_state_upgrade_tls(struct connectdata *conn)
485 struct imap_conn *imapc = &conn->proto.imapc;
488 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
492 result = imap_state_login(conn);
493 state(conn, IMAP_STOP);
499 /* for LOGIN responses */
500 static CURLcode imap_state_login_resp(struct connectdata *conn,
504 CURLcode result = CURLE_OK;
505 struct SessionHandle *data = conn->data;
507 (void)instate; /* no use for this yet */
509 if(imapcode != 'O') {
510 failf(data, "Access denied. %c", imapcode);
511 result = CURLE_LOGIN_DENIED;
514 state(conn, IMAP_STOP);
519 /* for the (first line of) FETCH BODY[TEXT] response */
520 static CURLcode imap_state_fetch_resp(struct connectdata *conn,
524 CURLcode result = CURLE_OK;
525 struct SessionHandle *data = conn->data;
526 struct imap_conn *imapc = &conn->proto.imapc;
527 struct FTP *imap = data->state.proto.imap;
528 struct pingpong *pp = &imapc->pp;
529 const char *ptr = data->state.buffer;
531 (void)instate; /* no use for this yet */
533 if('*' != imapcode) {
534 Curl_pgrsSetDownloadSize(data, 0);
535 state(conn, IMAP_STOP);
539 /* Something like this comes "* 1 FETCH (BODY[TEXT] {2021}\r" */
540 while(*ptr && (*ptr != '{'))
544 curl_off_t filesize = curlx_strtoofft(ptr+1, NULL, 10);
546 Curl_pgrsSetDownloadSize(data, filesize);
548 infof(data, "Found %" FORMAT_OFF_TU " bytes to download\n", filesize);
551 /* At this point there is a bunch of data in the header "cache" that is
552 actually body content, send it as body and then skip it. Do note
553 that there may even be additional "headers" after the body. */
554 size_t chunk = pp->cache_size;
556 if(chunk > (size_t)filesize)
557 /* the conversion from curl_off_t to size_t is always fine here */
558 chunk = (size_t)filesize;
560 result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
566 /* we've now used parts of or the entire cache */
567 if(pp->cache_size > chunk) {
568 /* part of, move the trailing data to the start and reduce the size */
569 memmove(pp->cache, pp->cache+chunk,
570 pp->cache_size - chunk);
571 pp->cache_size -= chunk;
574 /* cache is drained */
581 infof(data, "Filesize left: %" FORMAT_OFF_T "\n", filesize);
584 /* the entire data is already transferred! */
585 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
588 Curl_setup_transfer(conn, FIRSTSOCKET, filesize, FALSE,
589 imap->bytecountp, -1, NULL); /* no upload here */
591 data->req.maxdownload = filesize;
594 /* We don't know how to parse this line */
595 result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */
597 state(conn, IMAP_STOP);
602 /* start the DO phase */
603 static CURLcode imap_select(struct connectdata *conn)
605 CURLcode result = CURLE_OK;
606 struct imap_conn *imapc = &conn->proto.imapc;
609 str = getcmdid(conn);
611 result = imapsendf(conn, str, "%s SELECT %s", str,
612 imapc->mailbox?imapc->mailbox:"");
616 state(conn, IMAP_SELECT);
620 static CURLcode imap_fetch(struct connectdata *conn)
622 CURLcode result = CURLE_OK;
625 str = getcmdid(conn);
627 /* TODO: make this select the correct mail
628 * Use "1 body[text]" to get the full mail body of mail 1
630 result = imapsendf(conn, str, "%s FETCH 1 BODY[TEXT]", str);
635 * When issued, the server will respond with a single line similar to
636 * '* 1 FETCH (BODY[TEXT] {2021}'
638 * Identifying the fetch and how many bytes of contents we can expect. We
639 * must extract that number before continuing to "download as usual".
642 state(conn, IMAP_FETCH);
646 /* for SELECT responses */
647 static CURLcode imap_state_select_resp(struct connectdata *conn,
651 CURLcode result = CURLE_OK;
652 struct SessionHandle *data = conn->data;
653 (void)instate; /* no use for this yet */
655 if(imapcode != 'O') {
656 failf(data, "Select failed");
657 result = CURLE_LOGIN_DENIED;
660 result = imap_fetch(conn);
664 static CURLcode imap_statemach_act(struct connectdata *conn)
667 curl_socket_t sock = conn->sock[FIRSTSOCKET];
669 struct imap_conn *imapc = &conn->proto.imapc;
670 struct pingpong *pp = &imapc->pp;
673 /* busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */
674 if(imapc->state == IMAP_UPGRADETLS)
675 return imap_state_upgrade_tls(conn);
678 return Curl_pp_flushsend(pp);
680 /* we read a piece of response */
681 result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
686 /* we have now received a full IMAP server response */
687 switch(imapc->state) {
688 case IMAP_SERVERGREET:
689 result = imap_state_servergreet_resp(conn, imapcode, imapc->state);
693 result = imap_state_login_resp(conn, imapcode, imapc->state);
697 result = imap_state_starttls_resp(conn, imapcode, imapc->state);
701 result = imap_state_fetch_resp(conn, imapcode, imapc->state);
705 result = imap_state_select_resp(conn, imapcode, imapc->state);
709 /* fallthrough, just stop! */
712 state(conn, IMAP_STOP);
719 /* called repeatedly until done from multi.c */
720 static CURLcode imap_multi_statemach(struct connectdata *conn,
723 struct imap_conn *imapc = &conn->proto.imapc;
726 if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone)
727 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
729 result = Curl_pp_multi_statemach(&imapc->pp);
731 *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
736 static CURLcode imap_easy_statemach(struct connectdata *conn)
738 struct imap_conn *imapc = &conn->proto.imapc;
739 struct pingpong *pp = &imapc->pp;
740 CURLcode result = CURLE_OK;
742 while(imapc->state != IMAP_STOP) {
743 result = Curl_pp_easy_statemach(pp);
752 * Allocate and initialize the struct IMAP for the current SessionHandle. If
755 static CURLcode imap_init(struct connectdata *conn)
757 struct SessionHandle *data = conn->data;
758 struct FTP *imap = data->state.proto.imap;
760 imap = data->state.proto.imap = calloc(sizeof(struct FTP), 1);
762 return CURLE_OUT_OF_MEMORY;
765 /* get some initial data into the imap struct */
766 imap->bytecountp = &data->req.bytecount;
768 /* No need to duplicate user+password, the connectdata struct won't change
769 during a session, but we re-init them here since on subsequent inits
770 since the conn struct may have changed or been replaced.
772 imap->user = conn->user;
773 imap->passwd = conn->passwd;
779 * imap_connect() should do everything that is to be considered a part of
780 * the connection phase.
782 * The variable 'done' points to will be TRUE if the protocol-layer connect
783 * phase is done when this function returns, or FALSE is not. When called as
784 * a part of the easy interface, it will always be TRUE.
786 static CURLcode imap_connect(struct connectdata *conn,
787 bool *done) /* see description above */
790 struct imap_conn *imapc = &conn->proto.imapc;
791 struct SessionHandle *data=conn->data;
792 struct pingpong *pp = &imapc->pp;
794 *done = FALSE; /* default to not done yet */
796 /* If there already is a protocol-specific struct allocated for this
797 sessionhandle, deal with it */
798 Curl_reset_reqproto(conn);
800 result = imap_init(conn);
801 if(CURLE_OK != result)
804 /* We always support persistent connections on imap */
805 conn->bits.close = FALSE;
807 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
808 pp->statemach_act = imap_statemach_act;
809 pp->endofresp = imap_endofresp;
812 if((conn->handler->flags & PROTOPT_SSL) &&
813 data->state.used_interface != Curl_if_multi) {
815 result = Curl_ssl_connect(conn, FIRSTSOCKET);
820 Curl_pp_init(pp); /* init generic pingpong data */
822 /* When we connect, we start in the state where we await the server greeting
824 state(conn, IMAP_SERVERGREET);
825 imapc->idstr = "*"; /* we start off waiting for a '*' response */
827 if(data->state.used_interface == Curl_if_multi)
828 result = imap_multi_statemach(conn, done);
830 result = imap_easy_statemach(conn);
838 /***********************************************************************
842 * The DONE function. This does what needs to be done after a single DO has
845 * Input argument is already checked for validity.
847 static CURLcode imap_done(struct connectdata *conn, CURLcode status,
850 struct SessionHandle *data = conn->data;
851 struct FTP *imap = data->state.proto.imap;
852 CURLcode result=CURLE_OK;
856 /* When the easy handle is removed from the multi while libcurl is still
857 * trying to resolve the host name, it seems that the imap struct is not
858 * yet initialized, but the removal action calls Curl_done() which calls
859 * this function. So we simply return success if no imap pointer is set.
864 conn->bits.close = TRUE; /* marked for closure */
865 result = status; /* use the already set error code */
868 /* clear these for next connection */
869 imap->transfer = FTPTRANSFER_BODY;
874 /***********************************************************************
878 * This is the actual DO function for IMAP. Get a file/directory according to
879 * the options previously setup.
883 CURLcode imap_perform(struct connectdata *conn,
884 bool *connected, /* connect status after PASV / PORT */
887 /* this is IMAP and no proxy */
888 CURLcode result=CURLE_OK;
890 DEBUGF(infof(conn->data, "DO phase starts\n"));
892 if(conn->data->set.opt_no_body) {
893 /* requested no body means no transfer... */
894 struct FTP *imap = conn->data->state.proto.imap;
895 imap->transfer = FTPTRANSFER_INFO;
898 *dophase_done = FALSE; /* not done yet */
900 /* start the first command in the DO phase */
901 result = imap_select(conn);
905 /* run the state-machine */
906 if(conn->data->state.used_interface == Curl_if_multi)
907 result = imap_multi_statemach(conn, dophase_done);
909 result = imap_easy_statemach(conn);
910 *dophase_done = TRUE; /* with the easy interface we are done here */
912 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
915 DEBUGF(infof(conn->data, "DO phase is complete\n"));
920 /***********************************************************************
924 * This function is registered as 'curl_do' function. It decodes the path
925 * parts etc as a wrapper to the actual DO function (imap_perform).
927 * The input argument is already checked for validity.
929 static CURLcode imap_do(struct connectdata *conn, bool *done)
931 CURLcode retcode = CURLE_OK;
933 *done = FALSE; /* default to false */
936 Since connections can be re-used between SessionHandles, this might be a
937 connection already existing but on a fresh SessionHandle struct so we must
938 make sure we have a good 'struct IMAP' to play with. For new connections,
939 the struct IMAP is allocated and setup in the imap_connect() function.
941 Curl_reset_reqproto(conn);
942 retcode = imap_init(conn);
946 retcode = imap_parse_url_path(conn);
950 retcode = imap_regular_transfer(conn, done);
955 /***********************************************************************
959 * This should be called before calling sclose(). We should then wait for the
960 * response from the server before returning. The calling code should then try
961 * to close the connection.
964 static CURLcode imap_logout(struct connectdata *conn)
966 CURLcode result = CURLE_OK;
969 str = getcmdid(conn);
971 result = imapsendf(conn, str, "%s LOGOUT", str, NULL);
974 state(conn, IMAP_LOGOUT);
976 result = imap_easy_statemach(conn);
981 /***********************************************************************
985 * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
986 * resources. BLOCKING.
988 static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
990 struct imap_conn *imapc= &conn->proto.imapc;
992 /* The IMAP session may or may not have been allocated/setup at this
994 if(!dead_connection && imapc->pp.conn)
995 (void)imap_logout(conn); /* ignore errors on the LOGOUT */
997 Curl_pp_disconnect(&imapc->pp);
999 Curl_safefree(imapc->mailbox);
1004 /***********************************************************************
1006 * imap_parse_url_path()
1008 * Parse the URL path into separate path components.
1011 static CURLcode imap_parse_url_path(struct connectdata *conn)
1013 /* the imap struct is already inited in imap_connect() */
1014 struct imap_conn *imapc = &conn->proto.imapc;
1015 struct SessionHandle *data = conn->data;
1016 const char *path = data->state.path;
1021 /* url decode the path and use this mailbox */
1022 return Curl_urldecode(data, path, 0, &imapc->mailbox, NULL, TRUE);
1025 /* call this when the DO phase has completed */
1026 static CURLcode imap_dophase_done(struct connectdata *conn,
1029 struct FTP *imap = conn->data->state.proto.imap;
1032 if(imap->transfer != FTPTRANSFER_BODY)
1033 /* no data to transfer */
1034 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1039 /* called from multi.c while DOing */
1040 static CURLcode imap_doing(struct connectdata *conn,
1044 result = imap_multi_statemach(conn, dophase_done);
1047 result = imap_dophase_done(conn, FALSE /* not connected */);
1049 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1054 /***********************************************************************
1056 * imap_regular_transfer()
1058 * The input argument is already checked for validity.
1060 * Performs all commands done before a regular transfer between a local and a
1065 CURLcode imap_regular_transfer(struct connectdata *conn,
1068 CURLcode result=CURLE_OK;
1069 bool connected=FALSE;
1070 struct SessionHandle *data = conn->data;
1071 data->req.size = -1; /* make sure this is unknown at this point */
1073 Curl_pgrsSetUploadCounter(data, 0);
1074 Curl_pgrsSetDownloadCounter(data, 0);
1075 Curl_pgrsSetUploadSize(data, 0);
1076 Curl_pgrsSetDownloadSize(data, 0);
1078 result = imap_perform(conn,
1079 &connected, /* have we connected after PASV/PORT */
1080 dophase_done); /* all commands in the DO-phase done? */
1082 if(CURLE_OK == result) {
1085 /* the DO phase has not completed yet */
1088 result = imap_dophase_done(conn, connected);
1096 static CURLcode imap_setup_connection(struct connectdata * conn)
1098 struct SessionHandle *data = conn->data;
1100 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1101 /* Unless we have asked to tunnel imap operations through the proxy, we
1102 switch and use HTTP operations only */
1103 #ifndef CURL_DISABLE_HTTP
1104 if(conn->handler == &Curl_handler_imap)
1105 conn->handler = &Curl_handler_imap_proxy;
1108 conn->handler = &Curl_handler_imaps_proxy;
1110 failf(data, "IMAPS not supported!");
1111 return CURLE_UNSUPPORTED_PROTOCOL;
1115 * We explicitly mark this connection as persistent here as we're doing
1116 * IMAP over HTTP and thus we accidentally avoid setting this value
1119 conn->bits.close = FALSE;
1121 failf(data, "IMAP over http proxy requires HTTP support built-in!");
1122 return CURLE_UNSUPPORTED_PROTOCOL;
1126 data->state.path++; /* don't include the initial slash */
1131 #endif /* CURL_DISABLE_IMAP */