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 ***************************************************************************/
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>
60 #include "http.h" /* for HTTP proxy tunnel stuff */
64 #include "strtoofft.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: */
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, CURLcode status,
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, bool *dophase_done);
94 static CURLcode imap_setup_connection(struct connectdata *conn);
95 static CURLcode imap_state_upgrade_tls(struct connectdata *conn);
98 * IMAP protocol handler.
101 const struct Curl_handler Curl_handler_imap = {
103 imap_setup_connection, /* setup_connection */
105 imap_done, /* done */
106 ZERO_NULL, /* do_more */
107 imap_connect, /* connect_it */
108 imap_multi_statemach, /* connecting */
109 imap_doing, /* doing */
110 imap_getsock, /* proto_getsock */
111 imap_getsock, /* doing_getsock */
112 ZERO_NULL, /* domore_getsock */
113 ZERO_NULL, /* perform_getsock */
114 imap_disconnect, /* disconnect */
115 ZERO_NULL, /* readwrite */
116 PORT_IMAP, /* defport */
117 CURLPROTO_IMAP, /* protocol */
118 PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
119 | PROTOPT_NOURLQUERY /* flags */
125 * IMAPS protocol handler.
128 const struct Curl_handler Curl_handler_imaps = {
129 "IMAPS", /* scheme */
130 imap_setup_connection, /* setup_connection */
132 imap_done, /* done */
133 ZERO_NULL, /* do_more */
134 imap_connect, /* connect_it */
135 imap_multi_statemach, /* connecting */
136 imap_doing, /* doing */
137 imap_getsock, /* proto_getsock */
138 imap_getsock, /* doing_getsock */
139 ZERO_NULL, /* domore_getsock */
140 ZERO_NULL, /* perform_getsock */
141 imap_disconnect, /* disconnect */
142 ZERO_NULL, /* readwrite */
143 PORT_IMAPS, /* defport */
144 CURLPROTO_IMAP | CURLPROTO_IMAPS, /* protocol */
145 PROTOPT_CLOSEACTION | PROTOPT_SSL | PROTOPT_NEEDSPWD
146 | PROTOPT_NOURLQUERY /* flags */
150 #ifndef CURL_DISABLE_HTTP
152 * HTTP-proxyed IMAP protocol handler.
155 static const struct Curl_handler Curl_handler_imap_proxy = {
157 ZERO_NULL, /* setup_connection */
158 Curl_http, /* do_it */
159 Curl_http_done, /* done */
160 ZERO_NULL, /* do_more */
161 ZERO_NULL, /* connect_it */
162 ZERO_NULL, /* connecting */
163 ZERO_NULL, /* doing */
164 ZERO_NULL, /* proto_getsock */
165 ZERO_NULL, /* doing_getsock */
166 ZERO_NULL, /* domore_getsock */
167 ZERO_NULL, /* perform_getsock */
168 ZERO_NULL, /* disconnect */
169 ZERO_NULL, /* readwrite */
170 PORT_IMAP, /* defport */
171 CURLPROTO_HTTP, /* protocol */
172 PROTOPT_NONE /* flags */
178 * HTTP-proxyed IMAPS protocol handler.
181 static const struct Curl_handler Curl_handler_imaps_proxy = {
182 "IMAPS", /* scheme */
183 ZERO_NULL, /* setup_connection */
184 Curl_http, /* do_it */
185 Curl_http_done, /* done */
186 ZERO_NULL, /* do_more */
187 ZERO_NULL, /* connect_it */
188 ZERO_NULL, /* connecting */
189 ZERO_NULL, /* doing */
190 ZERO_NULL, /* proto_getsock */
191 ZERO_NULL, /* doing_getsock */
192 ZERO_NULL, /* domore_getsock */
193 ZERO_NULL, /* perform_getsock */
194 ZERO_NULL, /* disconnect */
195 ZERO_NULL, /* readwrite */
196 PORT_IMAPS, /* defport */
197 CURLPROTO_HTTP, /* protocol */
198 PROTOPT_NONE /* flags */
203 /***********************************************************************
207 * Sends the formated string as an IMAP command to the server.
209 * Designed to never block.
211 static CURLcode imap_sendf(struct connectdata *conn,
212 const char *idstr, /* command id to wait for */
213 const char *fmt, ...)
216 struct imap_conn *imapc = &conn->proto.imapc;
220 imapc->idstr = idstr;
222 res = Curl_pp_vsendf(&imapc->pp, fmt, ap);
229 static const char *getcmdid(struct connectdata *conn)
231 static const char * const ids[]= {
238 struct imap_conn *imapc = &conn->proto.imapc;
240 /* Get the next id, but wrap at end of table */
241 imapc->cmdid = (int)((imapc->cmdid + 1) % (sizeof(ids) / sizeof(ids[0])));
243 return ids[imapc->cmdid];
246 /***********************************************************************
250 * Checks the input string for characters that need escaping and returns an
251 * atom ready for sending to the server.
253 * The returned string needs to be freed.
256 static char* imap_atom(const char* str)
260 size_t backsp_count = 0;
261 size_t quote_count = 0;
262 bool space_exists = FALSE;
269 /* Count any unescapped characters */
282 /* Does the input contain any unescapped characters? */
283 if(!backsp_count && !quote_count && !space_exists)
286 /* Calculate the new string length */
287 newlen = strlen(str) + backsp_count + quote_count + (space_exists ? 2 : 0);
289 /* Allocate the new string */
290 newstr = (char *) malloc((newlen + 1) * sizeof(char));
294 /* Surround the string in quotes if necessary */
298 newstr[newlen - 1] = '"';
302 /* Copy the string, escaping backslash and quote characters along the way */
305 if(*p1 == '\\' || *p1 == '"') {
316 /* Terminate the string */
317 newstr[newlen] = '\0';
322 /* Function that checks for an ending imap status code at the start of the
324 static int imap_endofresp(struct pingpong *pp, int *resp)
326 char *line = pp->linestart_resp;
327 size_t len = pp->nread_resp;
328 struct imap_conn *imapc = &pp->conn->proto.imapc;
329 const char *id = imapc->idstr;
330 size_t id_len = strlen(id);
332 /* Do we have a generic command response? */
333 if(len >= id_len + 3) {
334 if(!memcmp(id, line, id_len) && line[id_len] == ' ') {
335 *resp = line[id_len + 1]; /* O, N or B */
340 /* Are we processing FETCH command responses? */
341 if(imapc->state == IMAP_FETCH) {
342 /* Do we have a valid response? */
343 if(len >= 2 && !memcmp("* ", line, 2)) {
349 return FALSE; /* nothing for us */
352 /* This is the ONLY way to change IMAP state! */
353 static void state(struct connectdata *conn,
356 struct imap_conn *imapc = &conn->proto.imapc;
357 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
358 /* for debug purposes */
359 static const char * const names[]={
371 if(imapc->state != newstate)
372 infof(conn->data, "IMAP %p state change from %s to %s\n",
373 imapc, names[imapc->state], names[newstate]);
376 imapc->state = newstate;
379 static CURLcode imap_state_login(struct connectdata *conn)
382 struct FTP *imap = conn->data->state.proto.imap;
383 const char *str = getcmdid(conn);
384 char *user = imap_atom(imap->user);
385 char *passwd = imap_atom(imap->passwd);
387 /* send USER and password */
388 result = imap_sendf(conn, str, "%s LOGIN %s %s", str,
389 user ? user : "", passwd ? passwd : "");
392 Curl_safefree(passwd);
397 state(conn, IMAP_LOGIN);
402 /* For the IMAP "protocol connect" and "doing" phases only */
403 static int imap_getsock(struct connectdata *conn,
404 curl_socket_t *socks,
407 return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks);
411 static void imap_to_imaps(struct connectdata *conn)
413 conn->handler = &Curl_handler_imaps;
416 #define imap_to_imaps(x) Curl_nop_stmt
419 /* For the initial server greeting */
420 static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
424 CURLcode result = CURLE_OK;
425 struct SessionHandle *data = conn->data;
427 (void)instate; /* no use for this yet */
429 if(imapcode != 'O') {
430 failf(data, "Got unexpected imap-server response");
431 return CURLE_FTP_WEIRD_SERVER_REPLY;
434 if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
435 /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
436 to TLS connection now */
437 const char *str = getcmdid(conn);
438 result = imap_sendf(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;
455 (void)instate; /* no use for this yet */
457 if(imapcode != 'O') {
458 if(data->set.use_ssl != CURLUSESSL_TRY) {
459 failf(data, "STARTTLS denied. %c", imapcode);
460 result = CURLE_USE_SSL_FAILED;
463 result = imap_state_login(conn);
466 if(data->state.used_interface == Curl_if_multi) {
467 state(conn, IMAP_UPGRADETLS);
468 result = imap_state_upgrade_tls(conn);
471 result = Curl_ssl_connect(conn, FIRSTSOCKET);
472 if(CURLE_OK == result) {
474 result = imap_state_login(conn);
482 static CURLcode imap_state_upgrade_tls(struct connectdata *conn)
484 struct imap_conn *imapc = &conn->proto.imapc;
487 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
491 result = imap_state_login(conn);
497 /* For LOGIN responses */
498 static CURLcode imap_state_login_resp(struct connectdata *conn,
502 CURLcode result = CURLE_OK;
503 struct SessionHandle *data = conn->data;
505 (void)instate; /* no use for this yet */
507 if(imapcode != 'O') {
508 failf(data, "Access denied. %c", imapcode);
509 result = CURLE_LOGIN_DENIED;
512 /* End of connect phase */
513 state(conn, IMAP_STOP);
518 /* Start the DO phase */
519 static CURLcode imap_select(struct connectdata *conn)
521 CURLcode result = CURLE_OK;
522 struct imap_conn *imapc = &conn->proto.imapc;
523 const char *str = getcmdid(conn);
525 result = imap_sendf(conn, str, "%s SELECT %s", str,
526 imapc->mailbox?imapc->mailbox:"");
530 state(conn, IMAP_SELECT);
535 static CURLcode imap_fetch(struct connectdata *conn)
537 CURLcode result = CURLE_OK;
538 const char *str = getcmdid(conn);
540 /* TODO: make this select the correct mail
541 * Use "1 body[text]" to get the full mail body of mail 1
543 result = imap_sendf(conn, str, "%s FETCH 1 BODY[TEXT]", str);
548 * When issued, the server will respond with a single line similar to
549 * '* 1 FETCH (BODY[TEXT] {2021}'
551 * Identifying the fetch and how many bytes of contents we can expect. We
552 * must extract that number before continuing to "download as usual".
555 state(conn, IMAP_FETCH);
560 /* For SELECT responses */
561 static CURLcode imap_state_select_resp(struct connectdata *conn,
565 CURLcode result = CURLE_OK;
566 struct SessionHandle *data = conn->data;
568 (void)instate; /* no use for this yet */
570 if(imapcode != 'O') {
571 failf(data, "Select failed");
572 result = CURLE_LOGIN_DENIED;
575 result = imap_fetch(conn);
580 /* For the (first line of) FETCH BODY[TEXT] response */
581 static CURLcode imap_state_fetch_resp(struct connectdata *conn,
585 CURLcode result = CURLE_OK;
586 struct SessionHandle *data = conn->data;
587 struct imap_conn *imapc = &conn->proto.imapc;
588 struct FTP *imap = data->state.proto.imap;
589 struct pingpong *pp = &imapc->pp;
590 const char *ptr = data->state.buffer;
592 (void)instate; /* no use for this yet */
594 if('*' != imapcode) {
595 Curl_pgrsSetDownloadSize(data, 0);
596 state(conn, IMAP_STOP);
600 /* Something like this comes "* 1 FETCH (BODY[TEXT] {2021}\r" */
601 while(*ptr && (*ptr != '{'))
605 curl_off_t filesize = curlx_strtoofft(ptr + 1, NULL, 10);
607 Curl_pgrsSetDownloadSize(data, filesize);
609 infof(data, "Found %" FORMAT_OFF_TU " bytes to download\n", filesize);
612 /* At this point there is a bunch of data in the header "cache" that is
613 actually body content, send it as body and then skip it. Do note
614 that there may even be additional "headers" after the body. */
615 size_t chunk = pp->cache_size;
617 if(chunk > (size_t)filesize)
618 /* the conversion from curl_off_t to size_t is always fine here */
619 chunk = (size_t)filesize;
621 result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
627 /* we've now used parts of or the entire cache */
628 if(pp->cache_size > chunk) {
629 /* part of, move the trailing data to the start and reduce the size */
630 memmove(pp->cache, pp->cache+chunk,
631 pp->cache_size - chunk);
632 pp->cache_size -= chunk;
635 /* cache is drained */
636 Curl_safefree(pp->cache);
642 infof(data, "Filesize left: %" FORMAT_OFF_T "\n", filesize);
645 /* the entire data is already transferred! */
646 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
649 Curl_setup_transfer(conn, FIRSTSOCKET, filesize, FALSE,
650 imap->bytecountp, -1, NULL); /* no upload here */
652 data->req.maxdownload = filesize;
655 /* We don't know how to parse this line */
656 result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */
658 /* End of do phase */
659 state(conn, IMAP_STOP);
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);
677 /* Flush any data that needs to be sent */
679 return Curl_pp_flushsend(pp);
681 /* Read the response from the server */
682 result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
687 /* We have now received a full IMAP server response */
688 switch(imapc->state) {
689 case IMAP_SERVERGREET:
690 result = imap_state_servergreet_resp(conn, imapcode, imapc->state);
694 result = imap_state_starttls_resp(conn, imapcode, imapc->state);
698 result = imap_state_login_resp(conn, imapcode, imapc->state);
702 result = imap_state_fetch_resp(conn, imapcode, imapc->state);
706 result = imap_state_select_resp(conn, imapcode, imapc->state);
710 /* fallthrough, just stop! */
713 state(conn, IMAP_STOP);
721 /* Called repeatedly until done from multi.c */
722 static CURLcode imap_multi_statemach(struct connectdata *conn,
725 struct imap_conn *imapc = &conn->proto.imapc;
728 if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone)
729 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
731 result = Curl_pp_multi_statemach(&imapc->pp);
733 *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
738 static CURLcode imap_easy_statemach(struct connectdata *conn)
740 struct imap_conn *imapc = &conn->proto.imapc;
741 struct pingpong *pp = &imapc->pp;
742 CURLcode result = CURLE_OK;
744 while(imapc->state != IMAP_STOP) {
745 result = Curl_pp_easy_statemach(pp);
753 /* 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;
761 imap = data->state.proto.imap = calloc(sizeof(struct FTP), 1);
763 return CURLE_OUT_OF_MEMORY;
766 /* Get some initial data into the imap struct */
767 imap->bytecountp = &data->req.bytecount;
769 /* No need to duplicate user+password, the connectdata struct won't change
770 during a session, but we re-init them here since on subsequent inits
771 since the conn struct may have changed or been replaced.
773 imap->user = conn->user;
774 imap->passwd = conn->passwd;
779 /***********************************************************************
781 * imap_connect() should do everything that is to be considered a part of
782 * the connection phase.
784 * The variable 'done' points to will be TRUE if the protocol-layer connect
785 * phase is done when this function returns, or FALSE is not. When called as
786 * a part of the easy interface, it will always be TRUE.
788 static CURLcode imap_connect(struct connectdata *conn,
789 bool *done) /* see description above */
792 struct imap_conn *imapc = &conn->proto.imapc;
793 struct SessionHandle *data=conn->data;
794 struct pingpong *pp = &imapc->pp;
796 *done = FALSE; /* default to not done yet */
798 /* If there already is a protocol-specific struct allocated for this
799 sessionhandle, deal with it */
800 Curl_reset_reqproto(conn);
802 result = imap_init(conn);
803 if(CURLE_OK != result)
806 /* We always support persistent connections on imap */
807 conn->bits.close = FALSE;
809 pp->response_time = RESP_TIMEOUT; /* set default response time-out */
810 pp->statemach_act = imap_statemach_act;
811 pp->endofresp = imap_endofresp;
814 if((conn->handler->flags & PROTOPT_SSL) &&
815 data->state.used_interface != Curl_if_multi) {
816 /* IMAPS is simply imap with SSL for the control channel */
817 /* so perform the SSL initialization for this socket */
818 result = Curl_ssl_connect(conn, FIRSTSOCKET);
823 /* Initialise the response reader stuff */
826 /* Start off waiting for the server greeting response */
827 state(conn, IMAP_SERVERGREET);
829 /* Start off with an id of '*' */
832 if(data->state.used_interface == Curl_if_multi)
833 result = imap_multi_statemach(conn, done);
835 result = imap_easy_statemach(conn);
843 /***********************************************************************
847 * The DONE function. This does what needs to be done after a single DO has
850 * Input argument is already checked for validity.
852 static CURLcode imap_done(struct connectdata *conn, CURLcode status,
855 struct SessionHandle *data = conn->data;
856 struct FTP *imap = data->state.proto.imap;
857 CURLcode result=CURLE_OK;
862 /* When the easy handle is removed from the multi while libcurl is still
863 * trying to resolve the host name, it seems that the imap struct is not
864 * yet initialized, but the removal action calls Curl_done() which calls
865 * this function. So we simply return success if no imap pointer is set.
870 conn->bits.close = TRUE; /* marked for closure */
871 result = status; /* use the already set error code */
874 /* Clear the transfer mode for the next connection */
875 imap->transfer = FTPTRANSFER_BODY;
880 /***********************************************************************
884 * This is the actual DO function for IMAP. Get a file/directory according to
885 * the options previously setup.
887 static CURLcode imap_perform(struct connectdata *conn, bool *connected,
890 /* This is IMAP and no proxy */
891 CURLcode result = CURLE_OK;
893 DEBUGF(infof(conn->data, "DO phase starts\n"));
895 if(conn->data->set.opt_no_body) {
896 /* Requested no body means no transfer */
897 struct FTP *imap = conn->data->state.proto.imap;
898 imap->transfer = FTPTRANSFER_INFO;
901 *dophase_done = FALSE; /* not done yet */
903 /* Start the first command in the DO phase */
904 result = imap_select(conn);
908 /* Run the state-machine */
909 if(conn->data->state.used_interface == Curl_if_multi)
910 result = imap_multi_statemach(conn, dophase_done);
912 result = imap_easy_statemach(conn);
913 *dophase_done = TRUE; /* with the easy interface we are done here */
915 *connected = conn->bits.tcpconnect[FIRSTSOCKET];
918 DEBUGF(infof(conn->data, "DO phase is complete\n"));
923 /***********************************************************************
927 * This function is registered as 'curl_do' function. It decodes the path
928 * parts etc as a wrapper to the actual DO function (imap_perform).
930 * The input argument is already checked for validity.
932 static CURLcode imap_do(struct connectdata *conn, bool *done)
934 CURLcode retcode = CURLE_OK;
936 *done = FALSE; /* default to false */
939 Since connections can be re-used between SessionHandles, this might be a
940 connection already existing but on a fresh SessionHandle struct so we must
941 make sure we have a good 'struct IMAP' to play with. For new connections,
942 the struct IMAP is allocated and setup in the imap_connect() function.
944 Curl_reset_reqproto(conn);
945 retcode = imap_init(conn);
949 /* Parse the URL path */
950 retcode = imap_parse_url_path(conn);
954 retcode = imap_regular_transfer(conn, done);
959 /***********************************************************************
963 * This should be called before calling sclose(). We should then wait for the
964 * response from the server before returning. The calling code should then try
965 * to close the connection.
968 static CURLcode imap_logout(struct connectdata *conn)
970 CURLcode result = CURLE_OK;
971 const char *str = getcmdid(conn);
973 result = imap_sendf(conn, str, "%s LOGOUT", str, NULL);
977 state(conn, IMAP_LOGOUT);
979 result = imap_easy_statemach(conn);
984 /***********************************************************************
988 * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
989 * resources. BLOCKING.
991 static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
993 struct imap_conn *imapc= &conn->proto.imapc;
995 /* We cannot send quit unconditionally. If this connection is stale or
996 bad in any way, sending quit and waiting around here will make the
997 disconnect wait in vain and cause more problems than we need to */
999 /* The IMAP session may or may not have been allocated/setup at this
1001 if(!dead_connection && imapc->pp.conn)
1002 (void)imap_logout(conn); /* ignore errors on the LOGOUT */
1004 /* Disconnect from the server */
1005 Curl_pp_disconnect(&imapc->pp);
1007 /* Cleanup our connection based variables */
1008 Curl_safefree(imapc->mailbox);
1013 /***********************************************************************
1015 * imap_parse_url_path()
1017 * Parse the URL path into separate path components.
1020 static CURLcode imap_parse_url_path(struct connectdata *conn)
1022 /* The imap struct is already inited in imap_connect() */
1023 struct imap_conn *imapc = &conn->proto.imapc;
1024 struct SessionHandle *data = conn->data;
1025 const char *path = data->state.path;
1030 /* URL decode the path and use this mailbox */
1031 return Curl_urldecode(data, path, 0, &imapc->mailbox, NULL, TRUE);
1034 /* Call this when the DO phase has completed */
1035 static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
1037 struct FTP *imap = conn->data->state.proto.imap;
1041 if(imap->transfer != FTPTRANSFER_BODY)
1042 /* no data to transfer */
1043 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1048 /* Called from multi.c while DOing */
1049 static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done)
1051 CURLcode result = imap_multi_statemach(conn, dophase_done);
1054 DEBUGF(infof(conn->data, "DO phase failed\n"));
1057 result = imap_dophase_done(conn, FALSE /* not connected */);
1059 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1066 /***********************************************************************
1068 * imap_regular_transfer()
1070 * The input argument is already checked for validity.
1072 * Performs all commands done before a regular transfer between a local and a
1075 static CURLcode imap_regular_transfer(struct connectdata *conn,
1078 CURLcode result = CURLE_OK;
1079 bool connected = FALSE;
1080 struct SessionHandle *data = conn->data;
1082 /* Make sure size is unknown at this point */
1083 data->req.size = -1;
1085 Curl_pgrsSetUploadCounter(data, 0);
1086 Curl_pgrsSetDownloadCounter(data, 0);
1087 Curl_pgrsSetUploadSize(data, 0);
1088 Curl_pgrsSetDownloadSize(data, 0);
1090 result = imap_perform(conn, &connected, dophase_done);
1092 if(CURLE_OK == result) {
1094 /* The DO phase has not completed yet */
1097 result = imap_dophase_done(conn, connected);
1105 static CURLcode imap_setup_connection(struct connectdata * conn)
1107 struct SessionHandle *data = conn->data;
1109 if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1110 /* Unless we have asked to tunnel imap operations through the proxy, we
1111 switch and use HTTP operations only */
1112 #ifndef CURL_DISABLE_HTTP
1113 if(conn->handler == &Curl_handler_imap)
1114 conn->handler = &Curl_handler_imap_proxy;
1117 conn->handler = &Curl_handler_imaps_proxy;
1119 failf(data, "IMAPS not supported!");
1120 return CURLE_UNSUPPORTED_PROTOCOL;
1124 /* We explicitly mark this connection as persistent here as we're doing
1125 IMAP over HTTP and thus we accidentally avoid setting this value
1127 conn->bits.close = FALSE;
1129 failf(data, "IMAP over http proxy requires HTTP support built-in!");
1130 return CURLE_UNSUPPORTED_PROTOCOL;
1134 data->state.path++; /* don't include the initial slash */
1139 #endif /* CURL_DISABLE_IMAP */