Revert "Update to 7.40.1"
[platform/upstream/curl.git] / lib / ftp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 #include "curl_setup.h"
24
25 #ifndef CURL_DISABLE_FTP
26
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
29 #endif
30 #ifdef HAVE_ARPA_INET_H
31 #include <arpa/inet.h>
32 #endif
33 #ifdef HAVE_UTSNAME_H
34 #include <sys/utsname.h>
35 #endif
36 #ifdef HAVE_NETDB_H
37 #include <netdb.h>
38 #endif
39 #ifdef __VMS
40 #include <in.h>
41 #include <inet.h>
42 #endif
43
44 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
45 #undef in_addr_t
46 #define in_addr_t unsigned long
47 #endif
48
49 #include <curl/curl.h>
50 #include "urldata.h"
51 #include "sendf.h"
52 #include "if2ip.h"
53 #include "hostip.h"
54 #include "progress.h"
55 #include "transfer.h"
56 #include "escape.h"
57 #include "http.h" /* for HTTP proxy tunnel stuff */
58 #include "socks.h"
59 #include "ftp.h"
60 #include "fileinfo.h"
61 #include "ftplistparser.h"
62 #include "curl_sec.h"
63 #include "strtoofft.h"
64 #include "strequal.h"
65 #include "vtls/vtls.h"
66 #include "connect.h"
67 #include "strerror.h"
68 #include "inet_ntop.h"
69 #include "inet_pton.h"
70 #include "select.h"
71 #include "parsedate.h" /* for the week day and month names */
72 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
73 #include "multiif.h"
74 #include "url.h"
75 #include "rawstr.h"
76 #include "speedcheck.h"
77 #include "warnless.h"
78 #include "http_proxy.h"
79 #include "non-ascii.h"
80
81 #define _MPRINTF_REPLACE /* use our functions only */
82 #include <curl/mprintf.h>
83
84 #include "curl_memory.h"
85 /* The last #include file should be: */
86 #include "memdebug.h"
87
88 #ifndef NI_MAXHOST
89 #define NI_MAXHOST 1025
90 #endif
91 #ifndef INET_ADDRSTRLEN
92 #define INET_ADDRSTRLEN 16
93 #endif
94
95 #ifdef CURL_DISABLE_VERBOSE_STRINGS
96 #define ftp_pasv_verbose(a,b,c,d)  Curl_nop_stmt
97 #endif
98
99 /* Local API functions */
100 #ifndef DEBUGBUILD
101 static void _state(struct connectdata *conn,
102                    ftpstate newstate);
103 #define state(x,y) _state(x,y)
104 #else
105 static void _state(struct connectdata *conn,
106                    ftpstate newstate,
107                    int lineno);
108 #define state(x,y) _state(x,y,__LINE__)
109 #endif
110
111 static CURLcode ftp_sendquote(struct connectdata *conn,
112                               struct curl_slist *quote);
113 static CURLcode ftp_quit(struct connectdata *conn);
114 static CURLcode ftp_parse_url_path(struct connectdata *conn);
115 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
116 #ifndef CURL_DISABLE_VERBOSE_STRINGS
117 static void ftp_pasv_verbose(struct connectdata *conn,
118                              Curl_addrinfo *ai,
119                              char *newhost, /* ascii version */
120                              int port);
121 #endif
122 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
123 static CURLcode ftp_state_mdtm(struct connectdata *conn);
124 static CURLcode ftp_state_quote(struct connectdata *conn,
125                                 bool init, ftpstate instate);
126 static CURLcode ftp_nb_type(struct connectdata *conn,
127                             bool ascii, ftpstate newstate);
128 static int ftp_need_type(struct connectdata *conn,
129                          bool ascii);
130 static CURLcode ftp_do(struct connectdata *conn, bool *done);
131 static CURLcode ftp_done(struct connectdata *conn,
132                          CURLcode, bool premature);
133 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
134 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
135 static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
136 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
137 static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
138                        int numsocks);
139 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
140                               int numsocks);
141 static CURLcode ftp_doing(struct connectdata *conn,
142                           bool *dophase_done);
143 static CURLcode ftp_setup_connection(struct connectdata * conn);
144
145 static CURLcode init_wc_data(struct connectdata *conn);
146 static CURLcode wc_statemach(struct connectdata *conn);
147
148 static void wc_data_dtor(void *ptr);
149
150 static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
151
152 static CURLcode ftp_readresp(curl_socket_t sockfd,
153                              struct pingpong *pp,
154                              int *ftpcode,
155                              size_t *size);
156 static CURLcode ftp_dophase_done(struct connectdata *conn,
157                                  bool connected);
158
159 /* easy-to-use macro: */
160 #define PPSENDF(x,y,z)  if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \
161                               return result
162
163
164 /*
165  * FTP protocol handler.
166  */
167
168 const struct Curl_handler Curl_handler_ftp = {
169   "FTP",                           /* scheme */
170   ftp_setup_connection,            /* setup_connection */
171   ftp_do,                          /* do_it */
172   ftp_done,                        /* done */
173   ftp_do_more,                     /* do_more */
174   ftp_connect,                     /* connect_it */
175   ftp_multi_statemach,             /* connecting */
176   ftp_doing,                       /* doing */
177   ftp_getsock,                     /* proto_getsock */
178   ftp_getsock,                     /* doing_getsock */
179   ftp_domore_getsock,              /* domore_getsock */
180   ZERO_NULL,                       /* perform_getsock */
181   ftp_disconnect,                  /* disconnect */
182   ZERO_NULL,                       /* readwrite */
183   PORT_FTP,                        /* defport */
184   CURLPROTO_FTP,                   /* protocol */
185   PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
186   | PROTOPT_NOURLQUERY /* flags */
187 };
188
189
190 #ifdef USE_SSL
191 /*
192  * FTPS protocol handler.
193  */
194
195 const struct Curl_handler Curl_handler_ftps = {
196   "FTPS",                          /* scheme */
197   ftp_setup_connection,            /* setup_connection */
198   ftp_do,                          /* do_it */
199   ftp_done,                        /* done */
200   ftp_do_more,                     /* do_more */
201   ftp_connect,                     /* connect_it */
202   ftp_multi_statemach,             /* connecting */
203   ftp_doing,                       /* doing */
204   ftp_getsock,                     /* proto_getsock */
205   ftp_getsock,                     /* doing_getsock */
206   ftp_domore_getsock,              /* domore_getsock */
207   ZERO_NULL,                       /* perform_getsock */
208   ftp_disconnect,                  /* disconnect */
209   ZERO_NULL,                       /* readwrite */
210   PORT_FTPS,                       /* defport */
211   CURLPROTO_FTPS,                  /* protocol */
212   PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
213   PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
214 };
215 #endif
216
217 #ifndef CURL_DISABLE_HTTP
218 /*
219  * HTTP-proxyed FTP protocol handler.
220  */
221
222 static const struct Curl_handler Curl_handler_ftp_proxy = {
223   "FTP",                                /* scheme */
224   Curl_http_setup_conn,                 /* setup_connection */
225   Curl_http,                            /* do_it */
226   Curl_http_done,                       /* done */
227   ZERO_NULL,                            /* do_more */
228   ZERO_NULL,                            /* connect_it */
229   ZERO_NULL,                            /* connecting */
230   ZERO_NULL,                            /* doing */
231   ZERO_NULL,                            /* proto_getsock */
232   ZERO_NULL,                            /* doing_getsock */
233   ZERO_NULL,                            /* domore_getsock */
234   ZERO_NULL,                            /* perform_getsock */
235   ZERO_NULL,                            /* disconnect */
236   ZERO_NULL,                            /* readwrite */
237   PORT_FTP,                             /* defport */
238   CURLPROTO_HTTP,                       /* protocol */
239   PROTOPT_NONE                          /* flags */
240 };
241
242
243 #ifdef USE_SSL
244 /*
245  * HTTP-proxyed FTPS protocol handler.
246  */
247
248 static const struct Curl_handler Curl_handler_ftps_proxy = {
249   "FTPS",                               /* scheme */
250   Curl_http_setup_conn,                 /* setup_connection */
251   Curl_http,                            /* do_it */
252   Curl_http_done,                       /* done */
253   ZERO_NULL,                            /* do_more */
254   ZERO_NULL,                            /* connect_it */
255   ZERO_NULL,                            /* connecting */
256   ZERO_NULL,                            /* doing */
257   ZERO_NULL,                            /* proto_getsock */
258   ZERO_NULL,                            /* doing_getsock */
259   ZERO_NULL,                            /* domore_getsock */
260   ZERO_NULL,                            /* perform_getsock */
261   ZERO_NULL,                            /* disconnect */
262   ZERO_NULL,                            /* readwrite */
263   PORT_FTPS,                            /* defport */
264   CURLPROTO_HTTP,                       /* protocol */
265   PROTOPT_NONE                          /* flags */
266 };
267 #endif
268 #endif
269
270
271 /*
272  * NOTE: back in the old days, we added code in the FTP code that made NOBODY
273  * requests on files respond with headers passed to the client/stdout that
274  * looked like HTTP ones.
275  *
276  * This approach is not very elegant, it causes confusion and is error-prone.
277  * It is subject for removal at the next (or at least a future) soname bump.
278  * Until then you can test the effects of the removal by undefining the
279  * following define named CURL_FTP_HTTPSTYLE_HEAD.
280  */
281 #define CURL_FTP_HTTPSTYLE_HEAD 1
282
283 static void freedirs(struct ftp_conn *ftpc)
284 {
285   int i;
286   if(ftpc->dirs) {
287     for(i=0; i < ftpc->dirdepth; i++) {
288       if(ftpc->dirs[i]) {
289         free(ftpc->dirs[i]);
290         ftpc->dirs[i]=NULL;
291       }
292     }
293     free(ftpc->dirs);
294     ftpc->dirs = NULL;
295     ftpc->dirdepth = 0;
296   }
297   if(ftpc->file) {
298     free(ftpc->file);
299     ftpc->file = NULL;
300   }
301 }
302
303 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
304    which are not allowed within RFC 959 <string>.
305    Note: The input string is in the client's encoding which might
306    not be ASCII, so escape sequences \r & \n must be used instead
307    of hex values 0x0d & 0x0a.
308 */
309 static bool isBadFtpString(const char *string)
310 {
311   return ((NULL != strchr(string, '\r')) ||
312           (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
313 }
314
315 /***********************************************************************
316  *
317  * AcceptServerConnect()
318  *
319  * After connection request is received from the server this function is
320  * called to accept the connection and close the listening socket
321  *
322  */
323 static CURLcode AcceptServerConnect(struct connectdata *conn)
324 {
325   struct SessionHandle *data = conn->data;
326   curl_socket_t sock = conn->sock[SECONDARYSOCKET];
327   curl_socket_t s = CURL_SOCKET_BAD;
328 #ifdef ENABLE_IPV6
329   struct Curl_sockaddr_storage add;
330 #else
331   struct sockaddr_in add;
332 #endif
333   curl_socklen_t size = (curl_socklen_t) sizeof(add);
334
335   if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
336     size = sizeof(add);
337
338     s=accept(sock, (struct sockaddr *) &add, &size);
339   }
340   Curl_closesocket(conn, sock); /* close the first socket */
341
342   if(CURL_SOCKET_BAD == s) {
343     failf(data, "Error accept()ing server connect");
344     return CURLE_FTP_PORT_FAILED;
345   }
346   infof(data, "Connection accepted from server\n");
347
348   conn->sock[SECONDARYSOCKET] = s;
349   curlx_nonblock(s, TRUE); /* enable non-blocking */
350   conn->sock_accepted[SECONDARYSOCKET] = TRUE;
351
352   if(data->set.fsockopt) {
353     int error = 0;
354
355     /* activate callback for setting socket options */
356     error = data->set.fsockopt(data->set.sockopt_client,
357                                s,
358                                CURLSOCKTYPE_ACCEPT);
359
360     if(error) {
361       Curl_closesocket(conn, s); /* close the socket and bail out */
362       conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
363       return CURLE_ABORTED_BY_CALLBACK;
364     }
365   }
366
367   return CURLE_OK;
368
369 }
370
371 /*
372  * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
373  * waiting server to connect. If the value is negative, the timeout time has
374  * already elapsed.
375  *
376  * The start time is stored in progress.t_acceptdata - as set with
377  * Curl_pgrsTime(..., TIMER_STARTACCEPT);
378  *
379  */
380 static long ftp_timeleft_accept(struct SessionHandle *data)
381 {
382   long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
383   long other;
384   struct timeval now;
385
386   if(data->set.accepttimeout > 0)
387     timeout_ms = data->set.accepttimeout;
388
389   now = Curl_tvnow();
390
391   /* check if the generic timeout possibly is set shorter */
392   other =  Curl_timeleft(data, &now, FALSE);
393   if(other && (other < timeout_ms))
394     /* note that this also works fine for when other happens to be negative
395        due to it already having elapsed */
396     timeout_ms = other;
397   else {
398     /* subtract elapsed time */
399     timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
400     if(!timeout_ms)
401       /* avoid returning 0 as that means no timeout! */
402       return -1;
403   }
404
405   return timeout_ms;
406 }
407
408
409 /***********************************************************************
410  *
411  * ReceivedServerConnect()
412  *
413  * After allowing server to connect to us from data port, this function
414  * checks both data connection for connection establishment and ctrl
415  * connection for a negative response regarding a failure in connecting
416  *
417  */
418 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
419 {
420   struct SessionHandle *data = conn->data;
421   curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
422   curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
423   struct ftp_conn *ftpc = &conn->proto.ftpc;
424   struct pingpong *pp = &ftpc->pp;
425   int result;
426   long timeout_ms;
427   ssize_t nread;
428   int ftpcode;
429
430   *received = FALSE;
431
432   timeout_ms = ftp_timeleft_accept(data);
433   infof(data, "Checking for server connect\n");
434   if(timeout_ms < 0) {
435     /* if a timeout was already reached, bail out */
436     failf(data, "Accept timeout occurred while waiting server connect");
437     return CURLE_FTP_ACCEPT_TIMEOUT;
438   }
439
440   /* First check whether there is a cached response from server */
441   if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
442     /* Data connection could not be established, let's return */
443     infof(data, "There is negative response in cache while serv connect\n");
444     Curl_GetFTPResponse(&nread, conn, &ftpcode);
445     return CURLE_FTP_ACCEPT_FAILED;
446   }
447
448   result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
449
450   /* see if the connection request is already here */
451   switch (result) {
452   case -1: /* error */
453     /* let's die here */
454     failf(data, "Error while waiting for server connect");
455     return CURLE_FTP_ACCEPT_FAILED;
456   case 0:  /* Server connect is not received yet */
457     break; /* loop */
458   default:
459
460     if(result & CURL_CSELECT_IN2) {
461       infof(data, "Ready to accept data connection from server\n");
462       *received = TRUE;
463     }
464     else if(result & CURL_CSELECT_IN) {
465       infof(data, "Ctrl conn has data while waiting for data conn\n");
466       Curl_GetFTPResponse(&nread, conn, &ftpcode);
467
468       if(ftpcode/100 > 3)
469         return CURLE_FTP_ACCEPT_FAILED;
470
471       return CURLE_FTP_WEIRD_SERVER_REPLY;
472     }
473
474     break;
475   } /* switch() */
476
477   return CURLE_OK;
478 }
479
480
481 /***********************************************************************
482  *
483  * InitiateTransfer()
484  *
485  * After connection from server is accepted this function is called to
486  * setup transfer parameters and initiate the data transfer.
487  *
488  */
489 static CURLcode InitiateTransfer(struct connectdata *conn)
490 {
491   struct SessionHandle *data = conn->data;
492   struct FTP *ftp = data->req.protop;
493   CURLcode result = CURLE_OK;
494
495   if(conn->ssl[SECONDARYSOCKET].use) {
496     /* since we only have a plaintext TCP connection here, we must now
497      * do the TLS stuff */
498     infof(data, "Doing the SSL/TLS handshake on the data stream\n");
499     result = Curl_ssl_connect(conn, SECONDARYSOCKET);
500     if(result)
501       return result;
502   }
503
504   if(conn->proto.ftpc.state_saved == FTP_STOR) {
505     *(ftp->bytecountp)=0;
506
507     /* When we know we're uploading a specified file, we can get the file
508        size prior to the actual upload. */
509
510     Curl_pgrsSetUploadSize(data, data->state.infilesize);
511
512     /* set the SO_SNDBUF for the secondary socket for those who need it */
513     Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
514
515     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
516                         SECONDARYSOCKET, ftp->bytecountp);
517   }
518   else {
519     /* FTP download: */
520     Curl_setup_transfer(conn, SECONDARYSOCKET,
521                         conn->proto.ftpc.retr_size_saved, FALSE,
522                         ftp->bytecountp, -1, NULL); /* no upload here */
523   }
524
525   conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
526   state(conn, FTP_STOP);
527
528   return CURLE_OK;
529 }
530
531 /***********************************************************************
532  *
533  * AllowServerConnect()
534  *
535  * When we've issue the PORT command, we have told the server to connect to
536  * us. This function checks whether data connection is established if so it is
537  * accepted.
538  *
539  */
540 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
541 {
542   struct SessionHandle *data = conn->data;
543   long timeout_ms;
544   CURLcode ret = CURLE_OK;
545
546   *connected = FALSE;
547   infof(data, "Preparing for accepting server on data port\n");
548
549   /* Save the time we start accepting server connect */
550   Curl_pgrsTime(data, TIMER_STARTACCEPT);
551
552   timeout_ms = ftp_timeleft_accept(data);
553   if(timeout_ms < 0) {
554     /* if a timeout was already reached, bail out */
555     failf(data, "Accept timeout occurred while waiting server connect");
556     return CURLE_FTP_ACCEPT_TIMEOUT;
557   }
558
559   /* see if the connection request is already here */
560   ret = ReceivedServerConnect(conn, connected);
561   if(ret)
562     return ret;
563
564   if(*connected) {
565     ret = AcceptServerConnect(conn);
566     if(ret)
567       return ret;
568
569     ret = InitiateTransfer(conn);
570     if(ret)
571       return ret;
572   }
573   else {
574     /* Add timeout to multi handle and break out of the loop */
575     if(ret == CURLE_OK && *connected == FALSE) {
576       if(data->set.accepttimeout > 0)
577         Curl_expire(data, data->set.accepttimeout);
578       else
579         Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
580     }
581   }
582
583   return ret;
584 }
585
586 /* macro to check for a three-digit ftp status code at the start of the
587    given string */
588 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) &&       \
589                           ISDIGIT(line[2]))
590
591 /* macro to check for the last line in an FTP server response */
592 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
593
594 static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
595                           int *code)
596 {
597   (void)conn;
598
599   if((len > 3) && LASTLINE(line)) {
600     *code = curlx_sltosi(strtol(line, NULL, 10));
601     return TRUE;
602   }
603
604   return FALSE;
605 }
606
607 static CURLcode ftp_readresp(curl_socket_t sockfd,
608                              struct pingpong *pp,
609                              int *ftpcode, /* return the ftp-code if done */
610                              size_t *size) /* size of the response */
611 {
612   struct connectdata *conn = pp->conn;
613   struct SessionHandle *data = conn->data;
614 #ifdef HAVE_GSSAPI
615   char * const buf = data->state.buffer;
616 #endif
617   CURLcode result = CURLE_OK;
618   int code;
619
620   result = Curl_pp_readresp(sockfd, pp, &code, size);
621
622 #if defined(HAVE_GSSAPI)
623   /* handle the security-oriented responses 6xx ***/
624   /* FIXME: some errorchecking perhaps... ***/
625   switch(code) {
626   case 631:
627     code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
628     break;
629   case 632:
630     code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
631     break;
632   case 633:
633     code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
634     break;
635   default:
636     /* normal ftp stuff we pass through! */
637     break;
638   }
639 #endif
640
641   /* store the latest code for later retrieval */
642   data->info.httpcode=code;
643
644   if(ftpcode)
645     *ftpcode = code;
646
647   if(421 == code) {
648     /* 421 means "Service not available, closing control connection." and FTP
649      * servers use it to signal that idle session timeout has been exceeded.
650      * If we ignored the response, it could end up hanging in some cases.
651      *
652      * This response code can come at any point so having it treated
653      * generically is a good idea.
654      */
655     infof(data, "We got a 421 - timeout!\n");
656     state(conn, FTP_STOP);
657     return CURLE_OPERATION_TIMEDOUT;
658   }
659
660   return result;
661 }
662
663 /* --- parse FTP server responses --- */
664
665 /*
666  * Curl_GetFTPResponse() is a BLOCKING function to read the full response
667  * from a server after a command.
668  *
669  */
670
671 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
672                              struct connectdata *conn,
673                              int *ftpcode) /* return the ftp-code */
674 {
675   /*
676    * We cannot read just one byte per read() and then go back to select() as
677    * the OpenSSL read() doesn't grok that properly.
678    *
679    * Alas, read as much as possible, split up into lines, use the ending
680    * line in a response or continue reading.  */
681
682   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
683   long timeout;              /* timeout in milliseconds */
684   long interval_ms;
685   struct SessionHandle *data = conn->data;
686   CURLcode result = CURLE_OK;
687   struct ftp_conn *ftpc = &conn->proto.ftpc;
688   struct pingpong *pp = &ftpc->pp;
689   size_t nread;
690   int cache_skip=0;
691   int value_to_be_ignored=0;
692
693   if(ftpcode)
694     *ftpcode = 0; /* 0 for errors */
695   else
696     /* make the pointer point to something for the rest of this function */
697     ftpcode = &value_to_be_ignored;
698
699   *nreadp=0;
700
701   while(!*ftpcode && !result) {
702     /* check and reset timeout value every lap */
703     timeout = Curl_pp_state_timeout(pp);
704
705     if(timeout <=0 ) {
706       failf(data, "FTP response timeout");
707       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
708     }
709
710     interval_ms = 1000;  /* use 1 second timeout intervals */
711     if(timeout < interval_ms)
712       interval_ms = timeout;
713
714     /*
715      * Since this function is blocking, we need to wait here for input on the
716      * connection and only then we call the response reading function. We do
717      * timeout at least every second to make the timeout check run.
718      *
719      * A caution here is that the ftp_readresp() function has a cache that may
720      * contain pieces of a response from the previous invoke and we need to
721      * make sure we don't just wait for input while there is unhandled data in
722      * that cache. But also, if the cache is there, we call ftp_readresp() and
723      * the cache wasn't good enough to continue we must not just busy-loop
724      * around this function.
725      *
726      */
727
728     if(pp->cache && (cache_skip < 2)) {
729       /*
730        * There's a cache left since before. We then skipping the wait for
731        * socket action, unless this is the same cache like the previous round
732        * as then the cache was deemed not enough to act on and we then need to
733        * wait for more data anyway.
734        */
735     }
736     else {
737       switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) {
738       case -1: /* select() error, stop reading */
739         failf(data, "FTP response aborted due to select/poll error: %d",
740               SOCKERRNO);
741         return CURLE_RECV_ERROR;
742
743       case 0: /* timeout */
744         if(Curl_pgrsUpdate(conn))
745           return CURLE_ABORTED_BY_CALLBACK;
746         continue; /* just continue in our loop for the timeout duration */
747
748       default: /* for clarity */
749         break;
750       }
751     }
752     result = ftp_readresp(sockfd, pp, ftpcode, &nread);
753     if(result)
754       break;
755
756     if(!nread && pp->cache)
757       /* bump cache skip counter as on repeated skips we must wait for more
758          data */
759       cache_skip++;
760     else
761       /* when we got data or there is no cache left, we reset the cache skip
762          counter */
763       cache_skip=0;
764
765     *nreadp += nread;
766
767   } /* while there's buffer left and loop is requested */
768
769   pp->pending_resp = FALSE;
770
771   return result;
772 }
773
774 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
775   /* for debug purposes */
776 static const char * const ftp_state_names[]={
777   "STOP",
778   "WAIT220",
779   "AUTH",
780   "USER",
781   "PASS",
782   "ACCT",
783   "PBSZ",
784   "PROT",
785   "CCC",
786   "PWD",
787   "SYST",
788   "NAMEFMT",
789   "QUOTE",
790   "RETR_PREQUOTE",
791   "STOR_PREQUOTE",
792   "POSTQUOTE",
793   "CWD",
794   "MKD",
795   "MDTM",
796   "TYPE",
797   "LIST_TYPE",
798   "RETR_TYPE",
799   "STOR_TYPE",
800   "SIZE",
801   "RETR_SIZE",
802   "STOR_SIZE",
803   "REST",
804   "RETR_REST",
805   "PORT",
806   "PRET",
807   "PASV",
808   "LIST",
809   "RETR",
810   "STOR",
811   "QUIT"
812 };
813 #endif
814
815 /* This is the ONLY way to change FTP state! */
816 static void _state(struct connectdata *conn,
817                    ftpstate newstate
818 #ifdef DEBUGBUILD
819                    , int lineno
820 #endif
821   )
822 {
823   struct ftp_conn *ftpc = &conn->proto.ftpc;
824 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
825   if(ftpc->state != newstate)
826     infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
827           (void *)ftpc, lineno, ftp_state_names[ftpc->state],
828           ftp_state_names[newstate]);
829 #endif
830   ftpc->state = newstate;
831 }
832
833 static CURLcode ftp_state_user(struct connectdata *conn)
834 {
835   CURLcode result;
836   struct FTP *ftp = conn->data->req.protop;
837   /* send USER */
838   PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
839
840   state(conn, FTP_USER);
841   conn->data->state.ftp_trying_alternative = FALSE;
842
843   return CURLE_OK;
844 }
845
846 static CURLcode ftp_state_pwd(struct connectdata *conn)
847 {
848   CURLcode result;
849
850   /* send PWD to discover our entry point */
851   PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
852   state(conn, FTP_PWD);
853
854   return CURLE_OK;
855 }
856
857 /* For the FTP "protocol connect" and "doing" phases only */
858 static int ftp_getsock(struct connectdata *conn,
859                        curl_socket_t *socks,
860                        int numsocks)
861 {
862   return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
863 }
864
865 /* For the FTP "DO_MORE" phase only */
866 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
867                               int numsocks)
868 {
869   struct ftp_conn *ftpc = &conn->proto.ftpc;
870
871   if(!numsocks)
872     return GETSOCK_BLANK;
873
874   /* When in DO_MORE state, we could be either waiting for us to connect to a
875    * remote site, or we could wait for that site to connect to us. Or just
876    * handle ordinary commands.
877    */
878
879   if(FTP_STOP == ftpc->state) {
880     int bits = GETSOCK_READSOCK(0);
881
882     /* if stopped and still in this state, then we're also waiting for a
883        connect on the secondary connection */
884     socks[0] = conn->sock[FIRSTSOCKET];
885
886     if(!conn->data->set.ftp_use_port) {
887       int s;
888       int i;
889       /* PORT is used to tell the server to connect to us, and during that we
890          don't do happy eyeballs, but we do if we connect to the server */
891       for(s=1, i=0; i<2; i++) {
892         if(conn->tempsock[i] != CURL_SOCKET_BAD) {
893           socks[s] = conn->tempsock[i];
894           bits |= GETSOCK_WRITESOCK(s++);
895         }
896       }
897     }
898     else {
899       socks[1] = conn->sock[SECONDARYSOCKET];
900       bits |= GETSOCK_WRITESOCK(1);
901     }
902
903     return bits;
904   }
905   else
906     return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
907 }
908
909 /* This is called after the FTP_QUOTE state is passed.
910
911    ftp_state_cwd() sends the range of CWD commands to the server to change to
912    the correct directory. It may also need to send MKD commands to create
913    missing ones, if that option is enabled.
914 */
915 static CURLcode ftp_state_cwd(struct connectdata *conn)
916 {
917   CURLcode result = CURLE_OK;
918   struct ftp_conn *ftpc = &conn->proto.ftpc;
919
920   if(ftpc->cwddone)
921     /* already done and fine */
922     result = ftp_state_mdtm(conn);
923   else {
924     ftpc->count2 = 0; /* count2 counts failed CWDs */
925
926     /* count3 is set to allow a MKD to fail once. In the case when first CWD
927        fails and then MKD fails (due to another session raced it to create the
928        dir) this then allows for a second try to CWD to it */
929     ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
930
931     if(conn->bits.reuse && ftpc->entrypath) {
932       /* This is a re-used connection. Since we change directory to where the
933          transfer is taking place, we must first get back to the original dir
934          where we ended up after login: */
935       ftpc->count1 = 0; /* we count this as the first path, then we add one
936                           for all upcoming ones in the ftp->dirs[] array */
937       PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
938       state(conn, FTP_CWD);
939     }
940     else {
941       if(ftpc->dirdepth) {
942         ftpc->count1 = 1;
943         /* issue the first CWD, the rest is sent when the CWD responses are
944            received... */
945         PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
946         state(conn, FTP_CWD);
947       }
948       else {
949         /* No CWD necessary */
950         result = ftp_state_mdtm(conn);
951       }
952     }
953   }
954   return result;
955 }
956
957 typedef enum {
958   EPRT,
959   PORT,
960   DONE
961 } ftpport;
962
963 static CURLcode ftp_state_use_port(struct connectdata *conn,
964                                    ftpport fcmd) /* start with this */
965
966 {
967   CURLcode result = CURLE_OK;
968   struct ftp_conn *ftpc = &conn->proto.ftpc;
969   struct SessionHandle *data=conn->data;
970   curl_socket_t portsock= CURL_SOCKET_BAD;
971   char myhost[256] = "";
972
973   struct Curl_sockaddr_storage ss;
974   Curl_addrinfo *res, *ai;
975   curl_socklen_t sslen;
976   char hbuf[NI_MAXHOST];
977   struct sockaddr *sa=(struct sockaddr *)&ss;
978   struct sockaddr_in * const sa4 = (void *)sa;
979 #ifdef ENABLE_IPV6
980   struct sockaddr_in6 * const sa6 = (void *)sa;
981 #endif
982   char tmp[1024];
983   static const char mode[][5] = { "EPRT", "PORT" };
984   int rc;
985   int error;
986   char *host = NULL;
987   char *string_ftpport = data->set.str[STRING_FTPPORT];
988   struct Curl_dns_entry *h=NULL;
989   unsigned short port_min = 0;
990   unsigned short port_max = 0;
991   unsigned short port;
992   bool possibly_non_local = TRUE;
993
994   char *addr = NULL;
995
996   /* Step 1, figure out what is requested,
997    * accepted format :
998    * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
999    */
1000
1001   if(data->set.str[STRING_FTPPORT] &&
1002      (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
1003
1004 #ifdef ENABLE_IPV6
1005     size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
1006       INET6_ADDRSTRLEN : strlen(string_ftpport);
1007 #else
1008     size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
1009       INET_ADDRSTRLEN : strlen(string_ftpport);
1010 #endif
1011     char *ip_start = string_ftpport;
1012     char *ip_end = NULL;
1013     char *port_start = NULL;
1014     char *port_sep = NULL;
1015
1016     addr = calloc(addrlen+1, 1);
1017     if(!addr)
1018       return CURLE_OUT_OF_MEMORY;
1019
1020 #ifdef ENABLE_IPV6
1021     if(*string_ftpport == '[') {
1022       /* [ipv6]:port(-range) */
1023       ip_start = string_ftpport + 1;
1024       if((ip_end = strchr(string_ftpport, ']')) != NULL )
1025         strncpy(addr, ip_start, ip_end - ip_start);
1026     }
1027     else
1028 #endif
1029       if(*string_ftpport == ':') {
1030         /* :port */
1031         ip_end = string_ftpport;
1032     }
1033     else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
1034         /* either ipv6 or (ipv4|domain|interface):port(-range) */
1035 #ifdef ENABLE_IPV6
1036       if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1037         /* ipv6 */
1038         port_min = port_max = 0;
1039         strcpy(addr, string_ftpport);
1040         ip_end = NULL; /* this got no port ! */
1041       }
1042       else
1043 #endif
1044         /* (ipv4|domain|interface):port(-range) */
1045         strncpy(addr, string_ftpport, ip_end - ip_start );
1046     }
1047     else
1048       /* ipv4|interface */
1049       strcpy(addr, string_ftpport);
1050
1051     /* parse the port */
1052     if(ip_end != NULL) {
1053       if((port_start = strchr(ip_end, ':')) != NULL) {
1054         port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
1055         if((port_sep = strchr(port_start, '-')) != NULL) {
1056           port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1057         }
1058         else
1059           port_max = port_min;
1060       }
1061     }
1062
1063     /* correct errors like:
1064      *  :1234-1230
1065      *  :-4711 , in this case port_min is (unsigned)-1,
1066      *           therefore port_min > port_max for all cases
1067      *           but port_max = (unsigned)-1
1068      */
1069     if(port_min > port_max )
1070       port_min = port_max = 0;
1071
1072
1073     if(*addr != '\0') {
1074       /* attempt to get the address of the given interface name */
1075       switch(Curl_if2ip(conn->ip_addr->ai_family, conn->scope, addr,
1076                      hbuf, sizeof(hbuf))) {
1077         case IF2IP_NOT_FOUND:
1078           /* not an interface, use the given string as host name instead */
1079           host = addr;
1080           break;
1081         case IF2IP_AF_NOT_SUPPORTED:
1082           return CURLE_FTP_PORT_FAILED;
1083         case IF2IP_FOUND:
1084           host = hbuf; /* use the hbuf for host name */
1085       }
1086     }
1087     else
1088       /* there was only a port(-range) given, default the host */
1089       host = NULL;
1090   } /* data->set.ftpport */
1091
1092   if(!host) {
1093     /* not an interface and not a host name, get default by extracting
1094        the IP from the control connection */
1095
1096     sslen = sizeof(ss);
1097     if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1098       failf(data, "getsockname() failed: %s",
1099           Curl_strerror(conn, SOCKERRNO) );
1100       Curl_safefree(addr);
1101       return CURLE_FTP_PORT_FAILED;
1102     }
1103     switch(sa->sa_family) {
1104 #ifdef ENABLE_IPV6
1105     case AF_INET6:
1106       Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1107       break;
1108 #endif
1109     default:
1110       Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1111       break;
1112     }
1113     host = hbuf; /* use this host name */
1114     possibly_non_local = FALSE; /* we know it is local now */
1115   }
1116
1117   /* resolv ip/host to ip */
1118   rc = Curl_resolv(conn, host, 0, &h);
1119   if(rc == CURLRESOLV_PENDING)
1120     (void)Curl_resolver_wait_resolv(conn, &h);
1121   if(h) {
1122     res = h->addr;
1123     /* when we return from this function, we can forget about this entry
1124        to we can unlock it now already */
1125     Curl_resolv_unlock(data, h);
1126   } /* (h) */
1127   else
1128     res = NULL; /* failure! */
1129
1130   if(res == NULL) {
1131     failf(data, "failed to resolve the address provided to PORT: %s", host);
1132     Curl_safefree(addr);
1133     return CURLE_FTP_PORT_FAILED;
1134   }
1135
1136   Curl_safefree(addr);
1137   host = NULL;
1138
1139   /* step 2, create a socket for the requested address */
1140
1141   portsock = CURL_SOCKET_BAD;
1142   error = 0;
1143   for(ai = res; ai; ai = ai->ai_next) {
1144     result = Curl_socket(conn, ai, NULL, &portsock);
1145     if(result) {
1146       error = SOCKERRNO;
1147       continue;
1148     }
1149     break;
1150   }
1151   if(!ai) {
1152     failf(data, "socket failure: %s", Curl_strerror(conn, error));
1153     return CURLE_FTP_PORT_FAILED;
1154   }
1155
1156   /* step 3, bind to a suitable local address */
1157
1158   memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1159   sslen = ai->ai_addrlen;
1160
1161   for(port = port_min; port <= port_max;) {
1162     if(sa->sa_family == AF_INET)
1163       sa4->sin_port = htons(port);
1164 #ifdef ENABLE_IPV6
1165     else
1166       sa6->sin6_port = htons(port);
1167 #endif
1168     /* Try binding the given address. */
1169     if(bind(portsock, sa, sslen) ) {
1170       /* It failed. */
1171       error = SOCKERRNO;
1172       if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1173         /* The requested bind address is not local.  Use the address used for
1174          * the control connection instead and restart the port loop
1175          */
1176
1177         infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1178               Curl_strerror(conn, error) );
1179
1180         sslen = sizeof(ss);
1181         if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1182           failf(data, "getsockname() failed: %s",
1183                 Curl_strerror(conn, SOCKERRNO) );
1184           Curl_closesocket(conn, portsock);
1185           return CURLE_FTP_PORT_FAILED;
1186         }
1187         port = port_min;
1188         possibly_non_local = FALSE; /* don't try this again */
1189         continue;
1190       }
1191       else if(error != EADDRINUSE && error != EACCES) {
1192         failf(data, "bind(port=%hu) failed: %s", port,
1193               Curl_strerror(conn, error) );
1194         Curl_closesocket(conn, portsock);
1195         return CURLE_FTP_PORT_FAILED;
1196       }
1197     }
1198     else
1199       break;
1200
1201     port++;
1202   }
1203
1204   /* maybe all ports were in use already*/
1205   if(port > port_max) {
1206     failf(data, "bind() failed, we ran out of ports!");
1207     Curl_closesocket(conn, portsock);
1208     return CURLE_FTP_PORT_FAILED;
1209   }
1210
1211   /* get the name again after the bind() so that we can extract the
1212      port number it uses now */
1213   sslen = sizeof(ss);
1214   if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1215     failf(data, "getsockname() failed: %s",
1216           Curl_strerror(conn, SOCKERRNO) );
1217     Curl_closesocket(conn, portsock);
1218     return CURLE_FTP_PORT_FAILED;
1219   }
1220
1221   /* step 4, listen on the socket */
1222
1223   if(listen(portsock, 1)) {
1224     failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1225     Curl_closesocket(conn, portsock);
1226     return CURLE_FTP_PORT_FAILED;
1227   }
1228
1229   /* step 5, send the proper FTP command */
1230
1231   /* get a plain printable version of the numerical address to work with
1232      below */
1233   Curl_printable_address(ai, myhost, sizeof(myhost));
1234
1235 #ifdef ENABLE_IPV6
1236   if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1237     /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1238        request and enable EPRT again! */
1239     conn->bits.ftp_use_eprt = TRUE;
1240 #endif
1241
1242   for(; fcmd != DONE; fcmd++) {
1243
1244     if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1245       /* if disabled, goto next */
1246       continue;
1247
1248     if((PORT == fcmd) && sa->sa_family != AF_INET)
1249       /* PORT is ipv4 only */
1250       continue;
1251
1252     switch (sa->sa_family) {
1253     case AF_INET:
1254       port = ntohs(sa4->sin_port);
1255       break;
1256 #ifdef ENABLE_IPV6
1257     case AF_INET6:
1258       port = ntohs(sa6->sin6_port);
1259       break;
1260 #endif
1261     default:
1262       continue; /* might as well skip this */
1263     }
1264
1265     if(EPRT == fcmd) {
1266       /*
1267        * Two fine examples from RFC2428;
1268        *
1269        * EPRT |1|132.235.1.2|6275|
1270        *
1271        * EPRT |2|1080::8:800:200C:417A|5282|
1272        */
1273
1274       result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1275                              sa->sa_family == AF_INET?1:2,
1276                              myhost, port);
1277       if(result) {
1278         failf(data, "Failure sending EPRT command: %s",
1279               curl_easy_strerror(result));
1280         Curl_closesocket(conn, portsock);
1281         /* don't retry using PORT */
1282         ftpc->count1 = PORT;
1283         /* bail out */
1284         state(conn, FTP_STOP);
1285         return result;
1286       }
1287       break;
1288     }
1289     else if(PORT == fcmd) {
1290       char *source = myhost;
1291       char *dest = tmp;
1292
1293       /* translate x.x.x.x to x,x,x,x */
1294       while(source && *source) {
1295         if(*source == '.')
1296           *dest=',';
1297         else
1298           *dest = *source;
1299         dest++;
1300         source++;
1301       }
1302       *dest = 0;
1303       snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1304
1305       result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1306       if(result) {
1307         failf(data, "Failure sending PORT command: %s",
1308               curl_easy_strerror(result));
1309         Curl_closesocket(conn, portsock);
1310         /* bail out */
1311         state(conn, FTP_STOP);
1312         return result;
1313       }
1314       break;
1315     }
1316   }
1317
1318   /* store which command was sent */
1319   ftpc->count1 = fcmd;
1320
1321   /* we set the secondary socket variable to this for now, it is only so that
1322      the cleanup function will close it in case we fail before the true
1323      secondary stuff is made */
1324   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
1325     Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
1326   conn->sock[SECONDARYSOCKET] = portsock;
1327
1328   /* this tcpconnect assignment below is a hackish work-around to make the
1329      multi interface with active FTP work - as it will not wait for a
1330      (passive) connect in Curl_is_connected().
1331
1332      The *proper* fix is to make sure that the active connection from the
1333      server is done in a non-blocking way. Currently, it is still BLOCKING.
1334   */
1335   conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1336
1337   state(conn, FTP_PORT);
1338   return result;
1339 }
1340
1341 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1342 {
1343   struct ftp_conn *ftpc = &conn->proto.ftpc;
1344   CURLcode result = CURLE_OK;
1345   /*
1346     Here's the excecutive summary on what to do:
1347
1348     PASV is RFC959, expect:
1349     227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1350
1351     LPSV is RFC1639, expect:
1352     228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1353
1354     EPSV is RFC2428, expect:
1355     229 Entering Extended Passive Mode (|||port|)
1356
1357   */
1358
1359   static const char mode[][5] = { "EPSV", "PASV" };
1360   int modeoff;
1361
1362 #ifdef PF_INET6
1363   if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1364     /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1365        request and enable EPSV again! */
1366     conn->bits.ftp_use_epsv = TRUE;
1367 #endif
1368
1369   modeoff = conn->bits.ftp_use_epsv?0:1;
1370
1371   PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1372
1373   ftpc->count1 = modeoff;
1374   state(conn, FTP_PASV);
1375   infof(conn->data, "Connect data stream passively\n");
1376
1377   return result;
1378 }
1379
1380 /*
1381  * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
1382  *
1383  * REST is the last command in the chain of commands when a "head"-like
1384  * request is made. Thus, if an actual transfer is to be made this is where we
1385  * take off for real.
1386  */
1387 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
1388 {
1389   CURLcode result = CURLE_OK;
1390   struct FTP *ftp = conn->data->req.protop;
1391   struct SessionHandle *data = conn->data;
1392
1393   if(ftp->transfer != FTPTRANSFER_BODY) {
1394     /* doesn't transfer any data */
1395
1396     /* still possibly do PRE QUOTE jobs */
1397     state(conn, FTP_RETR_PREQUOTE);
1398     result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1399   }
1400   else if(data->set.ftp_use_port) {
1401     /* We have chosen to use the PORT (or similar) command */
1402     result = ftp_state_use_port(conn, EPRT);
1403   }
1404   else {
1405     /* We have chosen (this is default) to use the PASV (or similar) command */
1406     if(data->set.ftp_use_pret) {
1407       /* The user has requested that we send a PRET command
1408          to prepare the server for the upcoming PASV */
1409       if(!conn->proto.ftpc.file) {
1410         PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1411                 data->set.str[STRING_CUSTOMREQUEST]?
1412                 data->set.str[STRING_CUSTOMREQUEST]:
1413                 (data->set.ftp_list_only?"NLST":"LIST"));
1414       }
1415       else if(data->set.upload) {
1416         PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1417       }
1418       else {
1419         PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1420       }
1421       state(conn, FTP_PRET);
1422     }
1423     else {
1424       result = ftp_state_use_pasv(conn);
1425     }
1426   }
1427   return result;
1428 }
1429
1430 static CURLcode ftp_state_rest(struct connectdata *conn)
1431 {
1432   CURLcode result = CURLE_OK;
1433   struct FTP *ftp = conn->data->req.protop;
1434   struct ftp_conn *ftpc = &conn->proto.ftpc;
1435
1436   if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1437     /* if a "head"-like request is being made (on a file) */
1438
1439     /* Determine if server can respond to REST command and therefore
1440        whether it supports range */
1441     PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1442
1443     state(conn, FTP_REST);
1444   }
1445   else
1446     result = ftp_state_prepare_transfer(conn);
1447
1448   return result;
1449 }
1450
1451 static CURLcode ftp_state_size(struct connectdata *conn)
1452 {
1453   CURLcode result = CURLE_OK;
1454   struct FTP *ftp = conn->data->req.protop;
1455   struct ftp_conn *ftpc = &conn->proto.ftpc;
1456
1457   if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1458     /* if a "head"-like request is being made (on a file) */
1459
1460     /* we know ftpc->file is a valid pointer to a file name */
1461     PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1462
1463     state(conn, FTP_SIZE);
1464   }
1465   else
1466     result = ftp_state_rest(conn);
1467
1468   return result;
1469 }
1470
1471 static CURLcode ftp_state_list(struct connectdata *conn)
1472 {
1473   CURLcode result = CURLE_OK;
1474   struct SessionHandle *data = conn->data;
1475
1476   /* If this output is to be machine-parsed, the NLST command might be better
1477      to use, since the LIST command output is not specified or standard in any
1478      way. It has turned out that the NLST list output is not the same on all
1479      servers either... */
1480
1481   /*
1482      if FTPFILE_NOCWD was specified, we are currently in
1483      the user's home directory, so we should add the path
1484      as argument for the LIST / NLST / or custom command.
1485      Whether the server will support this, is uncertain.
1486
1487      The other ftp_filemethods will CWD into dir/dir/ first and
1488      then just do LIST (in that case: nothing to do here)
1489   */
1490   char *cmd,*lstArg,*slashPos;
1491
1492   lstArg = NULL;
1493   if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1494      data->state.path &&
1495      data->state.path[0] &&
1496      strchr(data->state.path,'/')) {
1497
1498     lstArg = strdup(data->state.path);
1499     if(!lstArg)
1500       return CURLE_OUT_OF_MEMORY;
1501
1502     /* Check if path does not end with /, as then we cut off the file part */
1503     if(lstArg[strlen(lstArg) - 1] != '/')  {
1504
1505       /* chop off the file part if format is dir/dir/file */
1506       slashPos = strrchr(lstArg,'/');
1507       if(slashPos)
1508         *(slashPos+1) = '\0';
1509     }
1510   }
1511
1512   cmd = aprintf( "%s%s%s",
1513                  data->set.str[STRING_CUSTOMREQUEST]?
1514                  data->set.str[STRING_CUSTOMREQUEST]:
1515                  (data->set.ftp_list_only?"NLST":"LIST"),
1516                  lstArg? " ": "",
1517                  lstArg? lstArg: "" );
1518
1519   if(!cmd) {
1520     if(lstArg)
1521       free(lstArg);
1522     return CURLE_OUT_OF_MEMORY;
1523   }
1524
1525   result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1526
1527   if(lstArg)
1528     free(lstArg);
1529
1530   free(cmd);
1531
1532   if(result != CURLE_OK)
1533     return result;
1534
1535   state(conn, FTP_LIST);
1536
1537   return result;
1538 }
1539
1540 static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
1541 {
1542   CURLcode result = CURLE_OK;
1543
1544   /* We've sent the TYPE, now we must send the list of prequote strings */
1545
1546   result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1547
1548   return result;
1549 }
1550
1551 static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
1552 {
1553   CURLcode result = CURLE_OK;
1554
1555   /* We've sent the TYPE, now we must send the list of prequote strings */
1556
1557   result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1558
1559   return result;
1560 }
1561
1562 static CURLcode ftp_state_type(struct connectdata *conn)
1563 {
1564   CURLcode result = CURLE_OK;
1565   struct FTP *ftp = conn->data->req.protop;
1566   struct SessionHandle *data = conn->data;
1567   struct ftp_conn *ftpc = &conn->proto.ftpc;
1568
1569   /* If we have selected NOBODY and HEADER, it means that we only want file
1570      information. Which in FTP can't be much more than the file size and
1571      date. */
1572   if(data->set.opt_no_body && ftpc->file &&
1573      ftp_need_type(conn, data->set.prefer_ascii)) {
1574     /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1575        may not support it! It is however the only way we have to get a file's
1576        size! */
1577
1578     ftp->transfer = FTPTRANSFER_INFO;
1579     /* this means no actual transfer will be made */
1580
1581     /* Some servers return different sizes for different modes, and thus we
1582        must set the proper type before we check the size */
1583     result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1584     if(result)
1585       return result;
1586   }
1587   else
1588     result = ftp_state_size(conn);
1589
1590   return result;
1591 }
1592
1593 /* This is called after the CWD commands have been done in the beginning of
1594    the DO phase */
1595 static CURLcode ftp_state_mdtm(struct connectdata *conn)
1596 {
1597   CURLcode result = CURLE_OK;
1598   struct SessionHandle *data = conn->data;
1599   struct ftp_conn *ftpc = &conn->proto.ftpc;
1600
1601   /* Requested time of file or time-depended transfer? */
1602   if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1603
1604     /* we have requested to get the modified-time of the file, this is a white
1605        spot as the MDTM is not mentioned in RFC959 */
1606     PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1607
1608     state(conn, FTP_MDTM);
1609   }
1610   else
1611     result = ftp_state_type(conn);
1612
1613   return result;
1614 }
1615
1616
1617 /* This is called after the TYPE and possible quote commands have been sent */
1618 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1619                                    bool sizechecked)
1620 {
1621   CURLcode result = CURLE_OK;
1622   struct FTP *ftp = conn->data->req.protop;
1623   struct SessionHandle *data = conn->data;
1624   struct ftp_conn *ftpc = &conn->proto.ftpc;
1625   int seekerr = CURL_SEEKFUNC_OK;
1626
1627   if((data->state.resume_from && !sizechecked) ||
1628      ((data->state.resume_from > 0) && sizechecked)) {
1629     /* we're about to continue the uploading of a file */
1630     /* 1. get already existing file's size. We use the SIZE command for this
1631        which may not exist in the server!  The SIZE command is not in
1632        RFC959. */
1633
1634     /* 2. This used to set REST. But since we can do append, we
1635        don't another ftp command. We just skip the source file
1636        offset and then we APPEND the rest on the file instead */
1637
1638     /* 3. pass file-size number of bytes in the source file */
1639     /* 4. lower the infilesize counter */
1640     /* => transfer as usual */
1641
1642     if(data->state.resume_from < 0 ) {
1643       /* Got no given size to start from, figure it out */
1644       PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1645       state(conn, FTP_STOR_SIZE);
1646       return result;
1647     }
1648
1649     /* enable append */
1650     data->set.ftp_append = TRUE;
1651
1652     /* Let's read off the proper amount of bytes from the input. */
1653     if(conn->seek_func) {
1654       seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1655                                 SEEK_SET);
1656     }
1657
1658     if(seekerr != CURL_SEEKFUNC_OK) {
1659       if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1660         failf(data, "Could not seek stream");
1661         return CURLE_FTP_COULDNT_USE_REST;
1662       }
1663       /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1664       else {
1665         curl_off_t passed=0;
1666         do {
1667           size_t readthisamountnow =
1668             (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1669             BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1670
1671           size_t actuallyread =
1672             conn->fread_func(data->state.buffer, 1, readthisamountnow,
1673                              conn->fread_in);
1674
1675           passed += actuallyread;
1676           if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1677             /* this checks for greater-than only to make sure that the
1678                CURL_READFUNC_ABORT return code still aborts */
1679             failf(data, "Failed to read data");
1680             return CURLE_FTP_COULDNT_USE_REST;
1681           }
1682         } while(passed < data->state.resume_from);
1683       }
1684     }
1685     /* now, decrease the size of the read */
1686     if(data->state.infilesize>0) {
1687       data->state.infilesize -= data->state.resume_from;
1688
1689       if(data->state.infilesize <= 0) {
1690         infof(data, "File already completely uploaded\n");
1691
1692         /* no data to transfer */
1693         Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1694
1695         /* Set ->transfer so that we won't get any error in
1696          * ftp_done() because we didn't transfer anything! */
1697         ftp->transfer = FTPTRANSFER_NONE;
1698
1699         state(conn, FTP_STOP);
1700         return CURLE_OK;
1701       }
1702     }
1703     /* we've passed, proceed as normal */
1704   } /* resume_from */
1705
1706   PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1707           ftpc->file);
1708
1709   state(conn, FTP_STOR);
1710
1711   return result;
1712 }
1713
1714 static CURLcode ftp_state_quote(struct connectdata *conn,
1715                                 bool init,
1716                                 ftpstate instate)
1717 {
1718   CURLcode result = CURLE_OK;
1719   struct SessionHandle *data = conn->data;
1720   struct FTP *ftp = data->req.protop;
1721   struct ftp_conn *ftpc = &conn->proto.ftpc;
1722   bool quote=FALSE;
1723   struct curl_slist *item;
1724
1725   switch(instate) {
1726   case FTP_QUOTE:
1727   default:
1728     item = data->set.quote;
1729     break;
1730   case FTP_RETR_PREQUOTE:
1731   case FTP_STOR_PREQUOTE:
1732     item = data->set.prequote;
1733     break;
1734   case FTP_POSTQUOTE:
1735     item = data->set.postquote;
1736     break;
1737   }
1738
1739   /*
1740    * This state uses:
1741    * 'count1' to iterate over the commands to send
1742    * 'count2' to store wether to allow commands to fail
1743    */
1744
1745   if(init)
1746     ftpc->count1 = 0;
1747   else
1748     ftpc->count1++;
1749
1750   if(item) {
1751     int i = 0;
1752
1753     /* Skip count1 items in the linked list */
1754     while((i< ftpc->count1) && item) {
1755       item = item->next;
1756       i++;
1757     }
1758     if(item) {
1759       char *cmd = item->data;
1760       if(cmd[0] == '*') {
1761         cmd++;
1762         ftpc->count2 = 1; /* the sent command is allowed to fail */
1763       }
1764       else
1765         ftpc->count2 = 0; /* failure means cancel operation */
1766
1767       PPSENDF(&ftpc->pp, "%s", cmd);
1768       state(conn, instate);
1769       quote = TRUE;
1770     }
1771   }
1772
1773   if(!quote) {
1774     /* No more quote to send, continue to ... */
1775     switch(instate) {
1776     case FTP_QUOTE:
1777     default:
1778       result = ftp_state_cwd(conn);
1779       break;
1780     case FTP_RETR_PREQUOTE:
1781       if(ftp->transfer != FTPTRANSFER_BODY)
1782         state(conn, FTP_STOP);
1783       else {
1784         if(ftpc->known_filesize != -1) {
1785           Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1786           result = ftp_state_retr(conn, ftpc->known_filesize);
1787         }
1788         else {
1789           PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1790           state(conn, FTP_RETR_SIZE);
1791         }
1792       }
1793       break;
1794     case FTP_STOR_PREQUOTE:
1795       result = ftp_state_ul_setup(conn, FALSE);
1796       break;
1797     case FTP_POSTQUOTE:
1798       break;
1799     }
1800   }
1801
1802   return result;
1803 }
1804
1805 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1806    problems */
1807 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1808 {
1809   CURLcode result = CURLE_OK;
1810   infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
1811   /* disable it for next transfer */
1812   conn->bits.ftp_use_epsv = FALSE;
1813   conn->data->state.errorbuf = FALSE; /* allow error message to get
1814                                          rewritten */
1815   PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
1816   conn->proto.ftpc.count1++;
1817   /* remain in/go to the FTP_PASV state */
1818   state(conn, FTP_PASV);
1819   return result;
1820 }
1821
1822 /*
1823  * Perform the necessary magic that needs to be done once the TCP connection
1824  * to the proxy has completed.
1825  */
1826 static CURLcode proxy_magic(struct connectdata *conn,
1827                             char *newhost, unsigned short newport,
1828                             bool *magicdone)
1829 {
1830   CURLcode result = CURLE_OK;
1831   struct SessionHandle *data=conn->data;
1832
1833   *magicdone = FALSE;
1834   switch(conn->proxytype) {
1835   case CURLPROXY_SOCKS5:
1836   case CURLPROXY_SOCKS5_HOSTNAME:
1837     result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost,
1838                          newport, SECONDARYSOCKET, conn);
1839     *magicdone = TRUE;
1840     break;
1841   case CURLPROXY_SOCKS4:
1842     result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1843                          SECONDARYSOCKET, conn, FALSE);
1844     *magicdone = TRUE;
1845     break;
1846   case CURLPROXY_SOCKS4A:
1847     result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1848                          SECONDARYSOCKET, conn, TRUE);
1849     *magicdone = TRUE;
1850     break;
1851   case CURLPROXY_HTTP:
1852   case CURLPROXY_HTTP_1_0:
1853     /* do nothing here. handled later. */
1854     break;
1855   default:
1856     failf(data, "unknown proxytype option given");
1857     result = CURLE_COULDNT_CONNECT;
1858     break;
1859   }
1860
1861   if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1862     /* BLOCKING */
1863     /* We want "seamless" FTP operations through HTTP proxy tunnel */
1864
1865     /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
1866      * member conn->proto.http; we want FTP through HTTP and we have to
1867      * change the member temporarily for connecting to the HTTP proxy. After
1868      * Curl_proxyCONNECT we have to set back the member to the original
1869      * struct FTP pointer
1870      */
1871     struct HTTP http_proxy;
1872     struct FTP *ftp_save = data->req.protop;
1873     memset(&http_proxy, 0, sizeof(http_proxy));
1874     data->req.protop = &http_proxy;
1875
1876     result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
1877
1878     data->req.protop = ftp_save;
1879
1880     if(result)
1881       return result;
1882
1883     if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
1884       /* the CONNECT procedure is not complete, the tunnel is not yet up */
1885       state(conn, FTP_STOP); /* this phase is completed */
1886       return result;
1887     }
1888     else
1889       *magicdone = TRUE;
1890   }
1891   return result;
1892 }
1893
1894 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1895                                     int ftpcode)
1896 {
1897   struct ftp_conn *ftpc = &conn->proto.ftpc;
1898   CURLcode result;
1899   struct SessionHandle *data=conn->data;
1900   struct Curl_dns_entry *addr=NULL;
1901   int rc;
1902   unsigned short connectport; /* the local port connect() should use! */
1903   char *str=&data->state.buffer[4];  /* start on the first letter */
1904
1905   if((ftpc->count1 == 0) &&
1906      (ftpcode == 229)) {
1907     /* positive EPSV response */
1908     char *ptr = strchr(str, '(');
1909     if(ptr) {
1910       unsigned int num;
1911       char separator[4];
1912       ptr++;
1913       if(5  == sscanf(ptr, "%c%c%c%u%c",
1914                       &separator[0],
1915                       &separator[1],
1916                       &separator[2],
1917                       &num,
1918                       &separator[3])) {
1919         const char sep1 = separator[0];
1920         int i;
1921
1922         /* The four separators should be identical, or else this is an oddly
1923            formatted reply and we bail out immediately. */
1924         for(i=1; i<4; i++) {
1925           if(separator[i] != sep1) {
1926             ptr=NULL; /* set to NULL to signal error */
1927             break;
1928           }
1929         }
1930         if(num > 0xffff) {
1931           failf(data, "Illegal port number in EPSV reply");
1932           return CURLE_FTP_WEIRD_PASV_REPLY;
1933         }
1934         if(ptr) {
1935           ftpc->newport = (unsigned short)(num & 0xffff);
1936
1937           if(conn->bits.tunnel_proxy ||
1938              conn->proxytype == CURLPROXY_SOCKS5 ||
1939              conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1940              conn->proxytype == CURLPROXY_SOCKS4 ||
1941              conn->proxytype == CURLPROXY_SOCKS4A)
1942             /* proxy tunnel -> use other host info because ip_addr_str is the
1943                proxy address not the ftp host */
1944             snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
1945                      conn->host.name);
1946           else
1947             /* use the same IP we are already connected to */
1948             snprintf(ftpc->newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
1949         }
1950       }
1951       else
1952         ptr=NULL;
1953     }
1954     if(!ptr) {
1955       failf(data, "Weirdly formatted EPSV reply");
1956       return CURLE_FTP_WEIRD_PASV_REPLY;
1957     }
1958   }
1959   else if((ftpc->count1 == 1) &&
1960           (ftpcode == 227)) {
1961     /* positive PASV response */
1962     int ip[4];
1963     int port[2];
1964
1965     /*
1966      * Scan for a sequence of six comma-separated numbers and use them as
1967      * IP+port indicators.
1968      *
1969      * Found reply-strings include:
1970      * "227 Entering Passive Mode (127,0,0,1,4,51)"
1971      * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1972      * "227 Entering passive mode. 127,0,0,1,4,51"
1973      */
1974     while(*str) {
1975       if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1976                       &ip[0], &ip[1], &ip[2], &ip[3],
1977                       &port[0], &port[1]))
1978         break;
1979       str++;
1980     }
1981
1982     if(!*str) {
1983       failf(data, "Couldn't interpret the 227-response");
1984       return CURLE_FTP_WEIRD_227_FORMAT;
1985     }
1986
1987     /* we got OK from server */
1988     if(data->set.ftp_skip_ip) {
1989       /* told to ignore the remotely given IP but instead use the one we used
1990          for the control connection */
1991       infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
1992             ip[0], ip[1], ip[2], ip[3],
1993             conn->ip_addr_str);
1994       if(conn->bits.tunnel_proxy ||
1995          conn->proxytype == CURLPROXY_SOCKS5 ||
1996          conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1997          conn->proxytype == CURLPROXY_SOCKS4 ||
1998          conn->proxytype == CURLPROXY_SOCKS4A)
1999         /* proxy tunnel -> use other host info because ip_addr_str is the
2000            proxy address not the ftp host */
2001         snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s", conn->host.name);
2002       else
2003         snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
2004                  conn->ip_addr_str);
2005     }
2006     else
2007       snprintf(ftpc->newhost, sizeof(ftpc->newhost),
2008                "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
2009     ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
2010   }
2011   else if(ftpc->count1 == 0) {
2012     /* EPSV failed, move on to PASV */
2013     return ftp_epsv_disable(conn);
2014   }
2015   else {
2016     failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
2017     return CURLE_FTP_WEIRD_PASV_REPLY;
2018   }
2019
2020   if(conn->bits.proxy) {
2021     /*
2022      * This connection uses a proxy and we need to connect to the proxy again
2023      * here. We don't want to rely on a former host lookup that might've
2024      * expired now, instead we remake the lookup here and now!
2025      */
2026     rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
2027     if(rc == CURLRESOLV_PENDING)
2028       /* BLOCKING, ignores the return code but 'addr' will be NULL in
2029          case of failure */
2030       (void)Curl_resolver_wait_resolv(conn, &addr);
2031
2032     connectport =
2033       (unsigned short)conn->port; /* we connect to the proxy's port */
2034
2035     if(!addr) {
2036       failf(data, "Can't resolve proxy host %s:%hu",
2037             conn->proxy.name, connectport);
2038       return CURLE_FTP_CANT_GET_HOST;
2039     }
2040   }
2041   else {
2042     /* normal, direct, ftp connection */
2043     rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
2044     if(rc == CURLRESOLV_PENDING)
2045       /* BLOCKING */
2046       (void)Curl_resolver_wait_resolv(conn, &addr);
2047
2048     connectport = ftpc->newport; /* we connect to the remote port */
2049
2050     if(!addr) {
2051       failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
2052       return CURLE_FTP_CANT_GET_HOST;
2053     }
2054   }
2055
2056   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
2057   result = Curl_connecthost(conn, addr);
2058
2059   Curl_resolv_unlock(data, addr); /* we're done using this address */
2060
2061   if(result) {
2062     if(ftpc->count1 == 0 && ftpcode == 229)
2063       return ftp_epsv_disable(conn);
2064
2065     return result;
2066   }
2067
2068
2069   /*
2070    * When this is used from the multi interface, this might've returned with
2071    * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2072    * connect to connect.
2073    */
2074
2075   if(data->set.verbose)
2076     /* this just dumps information about this second connection */
2077     ftp_pasv_verbose(conn, conn->ip_addr, ftpc->newhost, connectport);
2078
2079   conn->bits.do_more = TRUE;
2080   state(conn, FTP_STOP); /* this phase is completed */
2081
2082   return result;
2083 }
2084
2085 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2086                                     int ftpcode)
2087 {
2088   struct SessionHandle *data = conn->data;
2089   struct ftp_conn *ftpc = &conn->proto.ftpc;
2090   ftpport fcmd = (ftpport)ftpc->count1;
2091   CURLcode result = CURLE_OK;
2092
2093   if(ftpcode != 200) {
2094     /* the command failed */
2095
2096     if(EPRT == fcmd) {
2097       infof(data, "disabling EPRT usage\n");
2098       conn->bits.ftp_use_eprt = FALSE;
2099     }
2100     fcmd++;
2101
2102     if(fcmd == DONE) {
2103       failf(data, "Failed to do PORT");
2104       result = CURLE_FTP_PORT_FAILED;
2105     }
2106     else
2107       /* try next */
2108       result = ftp_state_use_port(conn, fcmd);
2109   }
2110   else {
2111     infof(data, "Connect data stream actively\n");
2112     state(conn, FTP_STOP); /* end of DO phase */
2113     result = ftp_dophase_done(conn, FALSE);
2114   }
2115
2116   return result;
2117 }
2118
2119 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2120                                     int ftpcode)
2121 {
2122   CURLcode result = CURLE_OK;
2123   struct SessionHandle *data=conn->data;
2124   struct FTP *ftp = data->req.protop;
2125   struct ftp_conn *ftpc = &conn->proto.ftpc;
2126
2127   switch(ftpcode) {
2128   case 213:
2129     {
2130       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2131          last .sss part is optional and means fractions of a second */
2132       int year, month, day, hour, minute, second;
2133       char *buf = data->state.buffer;
2134       if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
2135                      &year, &month, &day, &hour, &minute, &second)) {
2136         /* we have a time, reformat it */
2137         time_t secs=time(NULL);
2138         /* using the good old yacc/bison yuck */
2139         snprintf(buf, sizeof(conn->data->state.buffer),
2140                  "%04d%02d%02d %02d:%02d:%02d GMT",
2141                  year, month, day, hour, minute, second);
2142         /* now, convert this into a time() value: */
2143         data->info.filetime = (long)curl_getdate(buf, &secs);
2144       }
2145
2146 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2147       /* If we asked for a time of the file and we actually got one as well,
2148          we "emulate" a HTTP-style header in our output. */
2149
2150       if(data->set.opt_no_body &&
2151          ftpc->file &&
2152          data->set.get_filetime &&
2153          (data->info.filetime>=0) ) {
2154         time_t filetime = (time_t)data->info.filetime;
2155         struct tm buffer;
2156         const struct tm *tm = &buffer;
2157
2158         result = Curl_gmtime(filetime, &buffer);
2159         if(result)
2160           return result;
2161
2162         /* format: "Tue, 15 Nov 1994 12:45:26" */
2163         snprintf(buf, BUFSIZE-1,
2164                  "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2165                  Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2166                  tm->tm_mday,
2167                  Curl_month[tm->tm_mon],
2168                  tm->tm_year + 1900,
2169                  tm->tm_hour,
2170                  tm->tm_min,
2171                  tm->tm_sec);
2172         result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2173         if(result)
2174           return result;
2175       } /* end of a ridiculous amount of conditionals */
2176 #endif
2177     }
2178     break;
2179   default:
2180     infof(data, "unsupported MDTM reply format\n");
2181     break;
2182   case 550: /* "No such file or directory" */
2183     failf(data, "Given file does not exist");
2184     result = CURLE_FTP_COULDNT_RETR_FILE;
2185     break;
2186   }
2187
2188   if(data->set.timecondition) {
2189     if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2190       switch(data->set.timecondition) {
2191       case CURL_TIMECOND_IFMODSINCE:
2192       default:
2193         if(data->info.filetime <= data->set.timevalue) {
2194           infof(data, "The requested document is not new enough\n");
2195           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2196           data->info.timecond = TRUE;
2197           state(conn, FTP_STOP);
2198           return CURLE_OK;
2199         }
2200         break;
2201       case CURL_TIMECOND_IFUNMODSINCE:
2202         if(data->info.filetime > data->set.timevalue) {
2203           infof(data, "The requested document is not old enough\n");
2204           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2205           data->info.timecond = TRUE;
2206           state(conn, FTP_STOP);
2207           return CURLE_OK;
2208         }
2209         break;
2210       } /* switch */
2211     }
2212     else {
2213       infof(data, "Skipping time comparison\n");
2214     }
2215   }
2216
2217   if(!result)
2218     result = ftp_state_type(conn);
2219
2220   return result;
2221 }
2222
2223 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2224                                     int ftpcode,
2225                                     ftpstate instate)
2226 {
2227   CURLcode result = CURLE_OK;
2228   struct SessionHandle *data=conn->data;
2229
2230   if(ftpcode/100 != 2) {
2231     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2232        successful 'TYPE I'. While that is not as RFC959 says, it is still a
2233        positive response code and we allow that. */
2234     failf(data, "Couldn't set desired mode");
2235     return CURLE_FTP_COULDNT_SET_TYPE;
2236   }
2237   if(ftpcode != 200)
2238     infof(data, "Got a %03d response code instead of the assumed 200\n",
2239           ftpcode);
2240
2241   if(instate == FTP_TYPE)
2242     result = ftp_state_size(conn);
2243   else if(instate == FTP_LIST_TYPE)
2244     result = ftp_state_list(conn);
2245   else if(instate == FTP_RETR_TYPE)
2246     result = ftp_state_retr_prequote(conn);
2247   else if(instate == FTP_STOR_TYPE)
2248     result = ftp_state_stor_prequote(conn);
2249
2250   return result;
2251 }
2252
2253 static CURLcode ftp_state_retr(struct connectdata *conn,
2254                                          curl_off_t filesize)
2255 {
2256   CURLcode result = CURLE_OK;
2257   struct SessionHandle *data=conn->data;
2258   struct FTP *ftp = data->req.protop;
2259   struct ftp_conn *ftpc = &conn->proto.ftpc;
2260
2261   if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2262     failf(data, "Maximum file size exceeded");
2263     return CURLE_FILESIZE_EXCEEDED;
2264   }
2265   ftp->downloadsize = filesize;
2266
2267   if(data->state.resume_from) {
2268     /* We always (attempt to) get the size of downloads, so it is done before
2269        this even when not doing resumes. */
2270     if(filesize == -1) {
2271       infof(data, "ftp server doesn't support SIZE\n");
2272       /* We couldn't get the size and therefore we can't know if there really
2273          is a part of the file left to get, although the server will just
2274          close the connection when we start the connection so it won't cause
2275          us any harm, just not make us exit as nicely. */
2276     }
2277     else {
2278       /* We got a file size report, so we check that there actually is a
2279          part of the file left to get, or else we go home.  */
2280       if(data->state.resume_from< 0) {
2281         /* We're supposed to download the last abs(from) bytes */
2282         if(filesize < -data->state.resume_from) {
2283           failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2284                 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2285                 data->state.resume_from, filesize);
2286           return CURLE_BAD_DOWNLOAD_RESUME;
2287         }
2288         /* convert to size to download */
2289         ftp->downloadsize = -data->state.resume_from;
2290         /* download from where? */
2291         data->state.resume_from = filesize - ftp->downloadsize;
2292       }
2293       else {
2294         if(filesize < data->state.resume_from) {
2295           failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2296                 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2297                 data->state.resume_from, filesize);
2298           return CURLE_BAD_DOWNLOAD_RESUME;
2299         }
2300         /* Now store the number of bytes we are expected to download */
2301         ftp->downloadsize = filesize-data->state.resume_from;
2302       }
2303     }
2304
2305     if(ftp->downloadsize == 0) {
2306       /* no data to transfer */
2307       Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2308       infof(data, "File already completely downloaded\n");
2309
2310       /* Set ->transfer so that we won't get any error in ftp_done()
2311        * because we didn't transfer the any file */
2312       ftp->transfer = FTPTRANSFER_NONE;
2313       state(conn, FTP_STOP);
2314       return CURLE_OK;
2315     }
2316
2317     /* Set resume file transfer offset */
2318     infof(data, "Instructs server to resume from offset %"
2319           CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
2320
2321     PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2322             data->state.resume_from);
2323
2324     state(conn, FTP_RETR_REST);
2325   }
2326   else {
2327     /* no resume */
2328     PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2329     state(conn, FTP_RETR);
2330   }
2331
2332   return result;
2333 }
2334
2335 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2336                                     int ftpcode,
2337                                     ftpstate instate)
2338 {
2339   CURLcode result = CURLE_OK;
2340   struct SessionHandle *data=conn->data;
2341   curl_off_t filesize;
2342   char *buf = data->state.buffer;
2343
2344   /* get the size from the ascii string: */
2345   filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2346
2347   if(instate == FTP_SIZE) {
2348 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2349     if(-1 != filesize) {
2350       snprintf(buf, sizeof(data->state.buffer),
2351                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2352       result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2353       if(result)
2354         return result;
2355     }
2356 #endif
2357     Curl_pgrsSetDownloadSize(data, filesize);
2358     result = ftp_state_rest(conn);
2359   }
2360   else if(instate == FTP_RETR_SIZE) {
2361     Curl_pgrsSetDownloadSize(data, filesize);
2362     result = ftp_state_retr(conn, filesize);
2363   }
2364   else if(instate == FTP_STOR_SIZE) {
2365     data->state.resume_from = filesize;
2366     result = ftp_state_ul_setup(conn, TRUE);
2367   }
2368
2369   return result;
2370 }
2371
2372 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2373                                     int ftpcode,
2374                                     ftpstate instate)
2375 {
2376   CURLcode result = CURLE_OK;
2377   struct ftp_conn *ftpc = &conn->proto.ftpc;
2378
2379   switch(instate) {
2380   case FTP_REST:
2381   default:
2382 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2383     if(ftpcode == 350) {
2384       char buffer[24]= { "Accept-ranges: bytes\r\n" };
2385       result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2386       if(result)
2387         return result;
2388     }
2389 #endif
2390     result = ftp_state_prepare_transfer(conn);
2391     break;
2392
2393   case FTP_RETR_REST:
2394     if(ftpcode != 350) {
2395       failf(conn->data, "Couldn't use REST");
2396       result = CURLE_FTP_COULDNT_USE_REST;
2397     }
2398     else {
2399       PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2400       state(conn, FTP_RETR);
2401     }
2402     break;
2403   }
2404
2405   return result;
2406 }
2407
2408 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2409                                     int ftpcode, ftpstate instate)
2410 {
2411   CURLcode result = CURLE_OK;
2412   struct SessionHandle *data = conn->data;
2413
2414   if(ftpcode>=400) {
2415     failf(data, "Failed FTP upload: %0d", ftpcode);
2416     state(conn, FTP_STOP);
2417     /* oops, we never close the sockets! */
2418     return CURLE_UPLOAD_FAILED;
2419   }
2420
2421   conn->proto.ftpc.state_saved = instate;
2422
2423   /* PORT means we are now awaiting the server to connect to us. */
2424   if(data->set.ftp_use_port) {
2425     bool connected;
2426
2427     state(conn, FTP_STOP); /* no longer in STOR state */
2428
2429     result = AllowServerConnect(conn, &connected);
2430     if(result)
2431       return result;
2432
2433     if(!connected) {
2434       struct ftp_conn *ftpc = &conn->proto.ftpc;
2435       infof(data, "Data conn was not available immediately\n");
2436       ftpc->wait_data_conn = TRUE;
2437     }
2438
2439     return CURLE_OK;
2440   }
2441   else
2442     return InitiateTransfer(conn);
2443 }
2444
2445 /* for LIST and RETR responses */
2446 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2447                                     int ftpcode,
2448                                     ftpstate instate)
2449 {
2450   CURLcode result = CURLE_OK;
2451   struct SessionHandle *data = conn->data;
2452   struct FTP *ftp = data->req.protop;
2453   char *buf = data->state.buffer;
2454
2455   if((ftpcode == 150) || (ftpcode == 125)) {
2456
2457     /*
2458       A;
2459       150 Opening BINARY mode data connection for /etc/passwd (2241
2460       bytes).  (ok, the file is being transferred)
2461
2462       B:
2463       150 Opening ASCII mode data connection for /bin/ls
2464
2465       C:
2466       150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2467
2468       D:
2469       150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2470
2471       E:
2472       125 Data connection already open; Transfer starting. */
2473
2474     curl_off_t size=-1; /* default unknown size */
2475
2476
2477     /*
2478      * It appears that there are FTP-servers that return size 0 for files when
2479      * SIZE is used on the file while being in BINARY mode. To work around
2480      * that (stupid) behavior, we attempt to parse the RETR response even if
2481      * the SIZE returned size zero.
2482      *
2483      * Debugging help from Salvatore Sorrentino on February 26, 2003.
2484      */
2485
2486     if((instate != FTP_LIST) &&
2487        !data->set.prefer_ascii &&
2488        (ftp->downloadsize < 1)) {
2489       /*
2490        * It seems directory listings either don't show the size or very
2491        * often uses size 0 anyway. ASCII transfers may very well turn out
2492        * that the transferred amount of data is not the same as this line
2493        * tells, why using this number in those cases only confuses us.
2494        *
2495        * Example D above makes this parsing a little tricky */
2496       char *bytes;
2497       bytes=strstr(buf, " bytes");
2498       if(bytes--) {
2499         long in=(long)(bytes-buf);
2500         /* this is a hint there is size information in there! ;-) */
2501         while(--in) {
2502           /* scan for the left parenthesis and break there */
2503           if('(' == *bytes)
2504             break;
2505           /* skip only digits */
2506           if(!ISDIGIT(*bytes)) {
2507             bytes=NULL;
2508             break;
2509           }
2510           /* one more estep backwards */
2511           bytes--;
2512         }
2513         /* if we have nothing but digits: */
2514         if(bytes++) {
2515           /* get the number! */
2516           size = curlx_strtoofft(bytes, NULL, 0);
2517         }
2518       }
2519     }
2520     else if(ftp->downloadsize > -1)
2521       size = ftp->downloadsize;
2522
2523     if(size > data->req.maxdownload && data->req.maxdownload > 0)
2524       size = data->req.size = data->req.maxdownload;
2525     else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2526       size = -1; /* kludge for servers that understate ASCII mode file size */
2527
2528     infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
2529           data->req.maxdownload);
2530
2531     if(instate != FTP_LIST)
2532       infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
2533             size);
2534
2535     /* FTP download: */
2536     conn->proto.ftpc.state_saved = instate;
2537     conn->proto.ftpc.retr_size_saved = size;
2538
2539     if(data->set.ftp_use_port) {
2540       bool connected;
2541
2542       result = AllowServerConnect(conn, &connected);
2543       if(result)
2544         return result;
2545
2546       if(!connected) {
2547         struct ftp_conn *ftpc = &conn->proto.ftpc;
2548         infof(data, "Data conn was not available immediately\n");
2549         state(conn, FTP_STOP);
2550         ftpc->wait_data_conn = TRUE;
2551       }
2552     }
2553     else
2554       return InitiateTransfer(conn);
2555   }
2556   else {
2557     if((instate == FTP_LIST) && (ftpcode == 450)) {
2558       /* simply no matching files in the dir listing */
2559       ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2560       state(conn, FTP_STOP); /* this phase is over */
2561     }
2562     else {
2563       failf(data, "RETR response: %03d", ftpcode);
2564       return instate == FTP_RETR && ftpcode == 550?
2565         CURLE_REMOTE_FILE_NOT_FOUND:
2566         CURLE_FTP_COULDNT_RETR_FILE;
2567     }
2568   }
2569
2570   return result;
2571 }
2572
2573 /* after USER, PASS and ACCT */
2574 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2575 {
2576   CURLcode result = CURLE_OK;
2577
2578   if(conn->ssl[FIRSTSOCKET].use) {
2579     /* PBSZ = PROTECTION BUFFER SIZE.
2580
2581     The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2582
2583     Specifically, the PROT command MUST be preceded by a PBSZ
2584     command and a PBSZ command MUST be preceded by a successful
2585     security data exchange (the TLS negotiation in this case)
2586
2587     ... (and on page 8):
2588
2589     Thus the PBSZ command must still be issued, but must have a
2590     parameter of '0' to indicate that no buffering is taking place
2591     and the data connection should not be encapsulated.
2592     */
2593     PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2594     state(conn, FTP_PBSZ);
2595   }
2596   else {
2597     result = ftp_state_pwd(conn);
2598   }
2599   return result;
2600 }
2601
2602 /* for USER and PASS responses */
2603 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2604                                     int ftpcode,
2605                                     ftpstate instate)
2606 {
2607   CURLcode result = CURLE_OK;
2608   struct SessionHandle *data = conn->data;
2609   struct FTP *ftp = data->req.protop;
2610   struct ftp_conn *ftpc = &conn->proto.ftpc;
2611   (void)instate; /* no use for this yet */
2612
2613   /* some need password anyway, and others just return 2xx ignored */
2614   if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2615     /* 331 Password required for ...
2616        (the server requires to send the user's password too) */
2617     PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2618     state(conn, FTP_PASS);
2619   }
2620   else if(ftpcode/100 == 2) {
2621     /* 230 User ... logged in.
2622        (the user logged in with or without password) */
2623     result = ftp_state_loggedin(conn);
2624   }
2625   else if(ftpcode == 332) {
2626     if(data->set.str[STRING_FTP_ACCOUNT]) {
2627       PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2628       state(conn, FTP_ACCT);
2629     }
2630     else {
2631       failf(data, "ACCT requested but none available");
2632       result = CURLE_LOGIN_DENIED;
2633     }
2634   }
2635   else {
2636     /* All other response codes, like:
2637
2638     530 User ... access denied
2639     (the server denies to log the specified user) */
2640
2641     if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2642         !conn->data->state.ftp_trying_alternative) {
2643       /* Ok, USER failed.  Let's try the supplied command. */
2644       PPSENDF(&conn->proto.ftpc.pp, "%s",
2645               conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2646       conn->data->state.ftp_trying_alternative = TRUE;
2647       state(conn, FTP_USER);
2648       result = CURLE_OK;
2649     }
2650     else {
2651       failf(data, "Access denied: %03d", ftpcode);
2652       result = CURLE_LOGIN_DENIED;
2653     }
2654   }
2655   return result;
2656 }
2657
2658 /* for ACCT response */
2659 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2660                                     int ftpcode)
2661 {
2662   CURLcode result = CURLE_OK;
2663   struct SessionHandle *data = conn->data;
2664   if(ftpcode != 230) {
2665     failf(data, "ACCT rejected by server: %03d", ftpcode);
2666     result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2667   }
2668   else
2669     result = ftp_state_loggedin(conn);
2670
2671   return result;
2672 }
2673
2674
2675 static CURLcode ftp_statemach_act(struct connectdata *conn)
2676 {
2677   CURLcode result;
2678   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2679   struct SessionHandle *data=conn->data;
2680   int ftpcode;
2681   struct ftp_conn *ftpc = &conn->proto.ftpc;
2682   struct pingpong *pp = &ftpc->pp;
2683   static const char ftpauth[][4]  = { "SSL", "TLS" };
2684   size_t nread = 0;
2685
2686   if(pp->sendleft)
2687     return Curl_pp_flushsend(pp);
2688
2689   result = ftp_readresp(sock, pp, &ftpcode, &nread);
2690   if(result)
2691     return result;
2692
2693   if(ftpcode) {
2694     /* we have now received a full FTP server response */
2695     switch(ftpc->state) {
2696     case FTP_WAIT220:
2697       if(ftpcode == 230)
2698         /* 230 User logged in - already! */
2699         return ftp_state_user_resp(conn, ftpcode, ftpc->state);
2700       else if(ftpcode != 220) {
2701         failf(data, "Got a %03d ftp-server response when 220 was expected",
2702               ftpcode);
2703         return CURLE_FTP_WEIRD_SERVER_REPLY;
2704       }
2705
2706       /* We have received a 220 response fine, now we proceed. */
2707 #ifdef HAVE_GSSAPI
2708       if(data->set.krb) {
2709         /* If not anonymous login, try a secure login. Note that this
2710            procedure is still BLOCKING. */
2711
2712         Curl_sec_request_prot(conn, "private");
2713         /* We set private first as default, in case the line below fails to
2714            set a valid level */
2715         Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2716
2717         if(Curl_sec_login(conn) != CURLE_OK)
2718           infof(data, "Logging in with password in cleartext!\n");
2719         else
2720           infof(data, "Authentication successful\n");
2721       }
2722 #endif
2723
2724       if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
2725         /* We don't have a SSL/TLS connection yet, but FTPS is
2726            requested. Try a FTPS connection now */
2727
2728         ftpc->count3=0;
2729         switch(data->set.ftpsslauth) {
2730         case CURLFTPAUTH_DEFAULT:
2731         case CURLFTPAUTH_SSL:
2732           ftpc->count2 = 1; /* add one to get next */
2733           ftpc->count1 = 0;
2734           break;
2735         case CURLFTPAUTH_TLS:
2736           ftpc->count2 = -1; /* subtract one to get next */
2737           ftpc->count1 = 1;
2738           break;
2739         default:
2740           failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2741                 (int)data->set.ftpsslauth);
2742           return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2743         }
2744         PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2745         state(conn, FTP_AUTH);
2746       }
2747       else {
2748         result = ftp_state_user(conn);
2749         if(result)
2750           return result;
2751       }
2752
2753       break;
2754
2755     case FTP_AUTH:
2756       /* we have gotten the response to a previous AUTH command */
2757
2758       /* RFC2228 (page 5) says:
2759        *
2760        * If the server is willing to accept the named security mechanism,
2761        * and does not require any security data, it must respond with
2762        * reply code 234/334.
2763        */
2764
2765       if((ftpcode == 234) || (ftpcode == 334)) {
2766         /* Curl_ssl_connect is BLOCKING */
2767         result = Curl_ssl_connect(conn, FIRSTSOCKET);
2768         if(CURLE_OK == result) {
2769           conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2770           result = ftp_state_user(conn);
2771         }
2772       }
2773       else if(ftpc->count3 < 1) {
2774         ftpc->count3++;
2775         ftpc->count1 += ftpc->count2; /* get next attempt */
2776         result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2777         /* remain in this same state */
2778       }
2779       else {
2780         if(data->set.use_ssl > CURLUSESSL_TRY)
2781           /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2782           result = CURLE_USE_SSL_FAILED;
2783         else
2784           /* ignore the failure and continue */
2785           result = ftp_state_user(conn);
2786       }
2787
2788       if(result)
2789         return result;
2790       break;
2791
2792     case FTP_USER:
2793     case FTP_PASS:
2794       result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2795       break;
2796
2797     case FTP_ACCT:
2798       result = ftp_state_acct_resp(conn, ftpcode);
2799       break;
2800
2801     case FTP_PBSZ:
2802       PPSENDF(&ftpc->pp, "PROT %c",
2803               data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2804       state(conn, FTP_PROT);
2805
2806       break;
2807
2808     case FTP_PROT:
2809       if(ftpcode/100 == 2)
2810         /* We have enabled SSL for the data connection! */
2811         conn->ssl[SECONDARYSOCKET].use =
2812           (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2813       /* FTP servers typically responds with 500 if they decide to reject
2814          our 'P' request */
2815       else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2816         /* we failed and bails out */
2817         return CURLE_USE_SSL_FAILED;
2818
2819       if(data->set.ftp_ccc) {
2820         /* CCC - Clear Command Channel
2821          */
2822         PPSENDF(&ftpc->pp, "%s", "CCC");
2823         state(conn, FTP_CCC);
2824       }
2825       else {
2826         result = ftp_state_pwd(conn);
2827         if(result)
2828           return result;
2829       }
2830       break;
2831
2832     case FTP_CCC:
2833       if(ftpcode < 500) {
2834         /* First shut down the SSL layer (note: this call will block) */
2835         result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2836
2837         if(result) {
2838           failf(conn->data, "Failed to clear the command channel (CCC)");
2839           return result;
2840         }
2841       }
2842
2843       /* Then continue as normal */
2844       result = ftp_state_pwd(conn);
2845       if(result)
2846         return result;
2847       break;
2848
2849     case FTP_PWD:
2850       if(ftpcode == 257) {
2851         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2852         char *dir;
2853         char *store;
2854
2855         dir = malloc(nread + 1);
2856         if(!dir)
2857           return CURLE_OUT_OF_MEMORY;
2858
2859         /* Reply format is like
2860            257<space>[rubbish]"<directory-name>"<space><commentary> and the
2861            RFC959 says
2862
2863            The directory name can contain any character; embedded
2864            double-quotes should be escaped by double-quotes (the
2865            "quote-doubling" convention).
2866         */
2867
2868         /* scan for the first double-quote for non-standard responses */
2869         while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
2870               && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2871           ptr++;
2872
2873         if('\"' == *ptr) {
2874           /* it started good */
2875           ptr++;
2876           for(store = dir; *ptr;) {
2877             if('\"' == *ptr) {
2878               if('\"' == ptr[1]) {
2879                 /* "quote-doubling" */
2880                 *store = ptr[1];
2881                 ptr++;
2882               }
2883               else {
2884                 /* end of path */
2885                 *store = '\0'; /* zero terminate */
2886                 break; /* get out of this loop */
2887               }
2888             }
2889             else
2890               *store = *ptr;
2891             store++;
2892             ptr++;
2893           }
2894
2895           /* If the path name does not look like an absolute path (i.e.: it
2896              does not start with a '/'), we probably need some server-dependent
2897              adjustments. For example, this is the case when connecting to
2898              an OS400 FTP server: this server supports two name syntaxes,
2899              the default one being incompatible with standard pathes. In
2900              addition, this server switches automatically to the regular path
2901              syntax when one is encountered in a command: this results in
2902              having an entrypath in the wrong syntax when later used in CWD.
2903                The method used here is to check the server OS: we do it only
2904              if the path name looks strange to minimize overhead on other
2905              systems. */
2906
2907           if(!ftpc->server_os && dir[0] != '/') {
2908
2909             result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
2910             if(result != CURLE_OK) {
2911               free(dir);
2912               return result;
2913             }
2914             Curl_safefree(ftpc->entrypath);
2915             ftpc->entrypath = dir; /* remember this */
2916             infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2917             /* also save it where getinfo can access it: */
2918             data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2919             state(conn, FTP_SYST);
2920             break;
2921           }
2922
2923           Curl_safefree(ftpc->entrypath);
2924           ftpc->entrypath = dir; /* remember this */
2925           infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2926           /* also save it where getinfo can access it: */
2927           data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2928         }
2929         else {
2930           /* couldn't get the path */
2931           free(dir);
2932           infof(data, "Failed to figure out path\n");
2933         }
2934       }
2935       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2936       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2937       break;
2938
2939     case FTP_SYST:
2940       if(ftpcode == 215) {
2941         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2942         char *os;
2943         char *store;
2944
2945         os = malloc(nread + 1);
2946         if(!os)
2947           return CURLE_OUT_OF_MEMORY;
2948
2949         /* Reply format is like
2950            215<space><OS-name><space><commentary>
2951         */
2952         while(*ptr == ' ')
2953           ptr++;
2954         for(store = os; *ptr && *ptr != ' ';)
2955           *store++ = *ptr++;
2956         *store = '\0'; /* zero terminate */
2957
2958         /* Check for special servers here. */
2959
2960         if(strequal(os, "OS/400")) {
2961           /* Force OS400 name format 1. */
2962           result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
2963           if(result != CURLE_OK) {
2964             free(os);
2965             return result;
2966           }
2967           /* remember target server OS */
2968           Curl_safefree(ftpc->server_os);
2969           ftpc->server_os = os;
2970           state(conn, FTP_NAMEFMT);
2971           break;
2972         }
2973         else {
2974           /* Nothing special for the target server. */
2975           /* remember target server OS */
2976           Curl_safefree(ftpc->server_os);
2977           ftpc->server_os = os;
2978         }
2979       }
2980       else {
2981         /* Cannot identify server OS. Continue anyway and cross fingers. */
2982       }
2983
2984       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2985       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2986       break;
2987
2988     case FTP_NAMEFMT:
2989       if(ftpcode == 250) {
2990         /* Name format change successful: reload initial path. */
2991         ftp_state_pwd(conn);
2992         break;
2993       }
2994
2995       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2996       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2997       break;
2998
2999     case FTP_QUOTE:
3000     case FTP_POSTQUOTE:
3001     case FTP_RETR_PREQUOTE:
3002     case FTP_STOR_PREQUOTE:
3003       if((ftpcode >= 400) && !ftpc->count2) {
3004         /* failure response code, and not allowed to fail */
3005         failf(conn->data, "QUOT command failed with %03d", ftpcode);
3006         return CURLE_QUOTE_ERROR;
3007       }
3008       result = ftp_state_quote(conn, FALSE, ftpc->state);
3009       if(result)
3010         return result;
3011
3012       break;
3013
3014     case FTP_CWD:
3015       if(ftpcode/100 != 2) {
3016         /* failure to CWD there */
3017         if(conn->data->set.ftp_create_missing_dirs &&
3018            ftpc->count1 && !ftpc->count2) {
3019           /* try making it */
3020           ftpc->count2++; /* counter to prevent CWD-MKD loops */
3021           PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
3022           state(conn, FTP_MKD);
3023         }
3024         else {
3025           /* return failure */
3026           failf(data, "Server denied you to change to the given directory");
3027           ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3028                                    to enter it */
3029           return CURLE_REMOTE_ACCESS_DENIED;
3030         }
3031       }
3032       else {
3033         /* success */
3034         ftpc->count2=0;
3035         if(++ftpc->count1 <= ftpc->dirdepth) {
3036           /* send next CWD */
3037           PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3038         }
3039         else {
3040           result = ftp_state_mdtm(conn);
3041           if(result)
3042             return result;
3043         }
3044       }
3045       break;
3046
3047     case FTP_MKD:
3048       if((ftpcode/100 != 2) && !ftpc->count3--) {
3049         /* failure to MKD the dir */
3050         failf(data, "Failed to MKD dir: %03d", ftpcode);
3051         return CURLE_REMOTE_ACCESS_DENIED;
3052       }
3053       state(conn, FTP_CWD);
3054       /* send CWD */
3055       PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3056       break;
3057
3058     case FTP_MDTM:
3059       result = ftp_state_mdtm_resp(conn, ftpcode);
3060       break;
3061
3062     case FTP_TYPE:
3063     case FTP_LIST_TYPE:
3064     case FTP_RETR_TYPE:
3065     case FTP_STOR_TYPE:
3066       result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3067       break;
3068
3069     case FTP_SIZE:
3070     case FTP_RETR_SIZE:
3071     case FTP_STOR_SIZE:
3072       result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3073       break;
3074
3075     case FTP_REST:
3076     case FTP_RETR_REST:
3077       result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3078       break;
3079
3080     case FTP_PRET:
3081       if(ftpcode != 200) {
3082         /* there only is this one standard OK return code. */
3083         failf(data, "PRET command not accepted: %03d", ftpcode);
3084         return CURLE_FTP_PRET_FAILED;
3085       }
3086       result = ftp_state_use_pasv(conn);
3087       break;
3088
3089     case FTP_PASV:
3090       result = ftp_state_pasv_resp(conn, ftpcode);
3091       break;
3092
3093     case FTP_PORT:
3094       result = ftp_state_port_resp(conn, ftpcode);
3095       break;
3096
3097     case FTP_LIST:
3098     case FTP_RETR:
3099       result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3100       break;
3101
3102     case FTP_STOR:
3103       result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3104       break;
3105
3106     case FTP_QUIT:
3107       /* fallthrough, just stop! */
3108     default:
3109       /* internal error */
3110       state(conn, FTP_STOP);
3111       break;
3112     }
3113   } /* if(ftpcode) */
3114
3115   return result;
3116 }
3117
3118
3119 /* called repeatedly until done from multi.c */
3120 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3121                                     bool *done)
3122 {
3123   struct ftp_conn *ftpc = &conn->proto.ftpc;
3124   CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
3125
3126   /* Check for the state outside of the Curl_socket_ready() return code checks
3127      since at times we are in fact already in this state when this function
3128      gets called. */
3129   *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3130
3131   return result;
3132 }
3133
3134 static CURLcode ftp_block_statemach(struct connectdata *conn)
3135 {
3136   struct ftp_conn *ftpc = &conn->proto.ftpc;
3137   struct pingpong *pp = &ftpc->pp;
3138   CURLcode result = CURLE_OK;
3139
3140   while(ftpc->state != FTP_STOP) {
3141     result = Curl_pp_statemach(pp, TRUE);
3142     if(result)
3143       break;
3144   }
3145
3146   return result;
3147 }
3148
3149 /*
3150  * ftp_connect() should do everything that is to be considered a part of
3151  * the connection phase.
3152  *
3153  * The variable 'done' points to will be TRUE if the protocol-layer connect
3154  * phase is done when this function returns, or FALSE if not.
3155  *
3156  */
3157 static CURLcode ftp_connect(struct connectdata *conn,
3158                                  bool *done) /* see description above */
3159 {
3160   CURLcode result;
3161   struct ftp_conn *ftpc = &conn->proto.ftpc;
3162   struct pingpong *pp = &ftpc->pp;
3163
3164   *done = FALSE; /* default to not done yet */
3165
3166   /* We always support persistent connections on ftp */
3167   connkeep(conn, "FTP default");
3168
3169   pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3170   pp->statemach_act = ftp_statemach_act;
3171   pp->endofresp = ftp_endofresp;
3172   pp->conn = conn;
3173
3174   if(conn->handler->flags & PROTOPT_SSL) {
3175     /* BLOCKING */
3176     result = Curl_ssl_connect(conn, FIRSTSOCKET);
3177     if(result)
3178       return result;
3179   }
3180
3181   Curl_pp_init(pp); /* init the generic pingpong data */
3182
3183   /* When we connect, we start in the state where we await the 220
3184      response */
3185   state(conn, FTP_WAIT220);
3186
3187   result = ftp_multi_statemach(conn, done);
3188
3189   return result;
3190 }
3191
3192 /***********************************************************************
3193  *
3194  * ftp_done()
3195  *
3196  * The DONE function. This does what needs to be done after a single DO has
3197  * performed.
3198  *
3199  * Input argument is already checked for validity.
3200  */
3201 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3202                               bool premature)
3203 {
3204   struct SessionHandle *data = conn->data;
3205   struct FTP *ftp = data->req.protop;
3206   struct ftp_conn *ftpc = &conn->proto.ftpc;
3207   struct pingpong *pp = &ftpc->pp;
3208   ssize_t nread;
3209   int ftpcode;
3210   CURLcode result = CURLE_OK;
3211   bool was_ctl_valid = ftpc->ctl_valid;
3212   char *path;
3213   const char *path_to_use = data->state.path;
3214
3215   if(!ftp)
3216     /* When the easy handle is removed from the multi while libcurl is still
3217      * trying to resolve the host name, it seems that the ftp struct is not
3218      * yet initialized, but the removal action calls Curl_done() which calls
3219      * this function. So we simply return success if no ftp pointer is set.
3220      */
3221     return CURLE_OK;
3222
3223   switch(status) {
3224   case CURLE_BAD_DOWNLOAD_RESUME:
3225   case CURLE_FTP_WEIRD_PASV_REPLY:
3226   case CURLE_FTP_PORT_FAILED:
3227   case CURLE_FTP_ACCEPT_FAILED:
3228   case CURLE_FTP_ACCEPT_TIMEOUT:
3229   case CURLE_FTP_COULDNT_SET_TYPE:
3230   case CURLE_FTP_COULDNT_RETR_FILE:
3231   case CURLE_PARTIAL_FILE:
3232   case CURLE_UPLOAD_FAILED:
3233   case CURLE_REMOTE_ACCESS_DENIED:
3234   case CURLE_FILESIZE_EXCEEDED:
3235   case CURLE_REMOTE_FILE_NOT_FOUND:
3236   case CURLE_WRITE_ERROR:
3237     /* the connection stays alive fine even though this happened */
3238     /* fall-through */
3239   case CURLE_OK: /* doesn't affect the control connection's status */
3240     if(!premature) {
3241       ftpc->ctl_valid = was_ctl_valid;
3242       break;
3243     }
3244     /* until we cope better with prematurely ended requests, let them
3245      * fallback as if in complete failure */
3246   default:       /* by default, an error means the control connection is
3247                     wedged and should not be used anymore */
3248     ftpc->ctl_valid = FALSE;
3249     ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3250                              current path, as this connection is going */
3251     connclose(conn, "FTP ended with bad error code");
3252     result = status;      /* use the already set error code */
3253     break;
3254   }
3255
3256   /* now store a copy of the directory we are in */
3257   if(ftpc->prevpath)
3258     free(ftpc->prevpath);
3259
3260   if(data->set.wildcardmatch) {
3261     if(data->set.chunk_end && ftpc->file) {
3262       data->set.chunk_end(data->wildcard.customptr);
3263     }
3264     ftpc->known_filesize = -1;
3265   }
3266
3267   /* get the "raw" path */
3268   path = curl_easy_unescape(data, path_to_use, 0, NULL);
3269   if(!path) {
3270     /* out of memory, but we can limp along anyway (and should try to
3271      * since we may already be in the out of memory cleanup path) */
3272     if(!result)
3273       result = CURLE_OUT_OF_MEMORY;
3274     ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3275     connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3276     ftpc->prevpath = NULL; /* no path remembering */
3277   }
3278   else {
3279     size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3280     size_t dlen = strlen(path)-flen;
3281     if(!ftpc->cwdfail) {
3282       if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3283         ftpc->prevpath = path;
3284         if(flen)
3285           /* if 'path' is not the whole string */
3286           ftpc->prevpath[dlen]=0; /* terminate */
3287       }
3288       else {
3289         /* we never changed dir */
3290         ftpc->prevpath=strdup("");
3291         free(path);
3292       }
3293       if(ftpc->prevpath)
3294         infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3295     }
3296     else {
3297       ftpc->prevpath = NULL; /* no path */
3298       free(path);
3299     }
3300   }
3301   /* free the dir tree and file parts */
3302   freedirs(ftpc);
3303
3304   /* shut down the socket to inform the server we're done */
3305
3306 #ifdef _WIN32_WCE
3307   shutdown(conn->sock[SECONDARYSOCKET],2);  /* SD_BOTH */
3308 #endif
3309
3310   if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3311     if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3312       /* partial download completed */
3313       result = Curl_pp_sendf(pp, "%s", "ABOR");
3314       if(result) {
3315         failf(data, "Failure sending ABOR command: %s",
3316               curl_easy_strerror(result));
3317         ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3318         connclose(conn, "ABOR command failed"); /* connection closure */
3319       }
3320     }
3321
3322     if(conn->ssl[SECONDARYSOCKET].use) {
3323       /* The secondary socket is using SSL so we must close down that part
3324          first before we close the socket for real */
3325       Curl_ssl_close(conn, SECONDARYSOCKET);
3326
3327       /* Note that we keep "use" set to TRUE since that (next) connection is
3328          still requested to use SSL */
3329     }
3330     if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3331       Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
3332       conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3333       conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
3334     }
3335   }
3336
3337   if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3338      pp->pending_resp && !premature) {
3339     /*
3340      * Let's see what the server says about the transfer we just performed,
3341      * but lower the timeout as sometimes this connection has died while the
3342      * data has been transferred. This happens when doing through NATs etc that
3343      * abandon old silent connections.
3344      */
3345     long old_time = pp->response_time;
3346
3347     pp->response_time = 60*1000; /* give it only a minute for now */
3348     pp->response = Curl_tvnow(); /* timeout relative now */
3349
3350     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3351
3352     pp->response_time = old_time; /* set this back to previous value */
3353
3354     if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3355       failf(data, "control connection looks dead");
3356       ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3357       connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3358     }
3359
3360     if(result)
3361       return result;
3362
3363     if(ftpc->dont_check && data->req.maxdownload > 0) {
3364       /* we have just sent ABOR and there is no reliable way to check if it was
3365        * successful or not; we have to close the connection now */
3366       infof(data, "partial download completed, closing connection\n");
3367       connclose(conn, "Partial download with no ability to check");
3368       return result;
3369     }
3370
3371     if(!ftpc->dont_check) {
3372       /* 226 Transfer complete, 250 Requested file action okay, completed. */
3373       if((ftpcode != 226) && (ftpcode != 250)) {
3374         failf(data, "server did not report OK, got %d", ftpcode);
3375         result = CURLE_PARTIAL_FILE;
3376       }
3377     }
3378   }
3379
3380   if(result || premature)
3381     /* the response code from the transfer showed an error already so no
3382        use checking further */
3383     ;
3384   else if(data->set.upload) {
3385     if((-1 != data->state.infilesize) &&
3386        (data->state.infilesize != *ftp->bytecountp) &&
3387        !data->set.crlf &&
3388        (ftp->transfer == FTPTRANSFER_BODY)) {
3389       failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3390             " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3391             *ftp->bytecountp, data->state.infilesize);
3392       result = CURLE_PARTIAL_FILE;
3393     }
3394   }
3395   else {
3396     if((-1 != data->req.size) &&
3397        (data->req.size != *ftp->bytecountp) &&
3398 #ifdef CURL_DO_LINEEND_CONV
3399        /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3400         * we'll check to see if the discrepancy can be explained by the number
3401         * of CRLFs we've changed to LFs.
3402         */
3403        ((data->req.size + data->state.crlf_conversions) !=
3404         *ftp->bytecountp) &&
3405 #endif /* CURL_DO_LINEEND_CONV */
3406        (data->req.maxdownload != *ftp->bytecountp)) {
3407       failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3408             " bytes", *ftp->bytecountp);
3409       result = CURLE_PARTIAL_FILE;
3410     }
3411     else if(!ftpc->dont_check &&
3412             !*ftp->bytecountp &&
3413             (data->req.size>0)) {
3414       failf(data, "No data was received!");
3415       result = CURLE_FTP_COULDNT_RETR_FILE;
3416     }
3417   }
3418
3419   /* clear these for next connection */
3420   ftp->transfer = FTPTRANSFER_BODY;
3421   ftpc->dont_check = FALSE;
3422
3423   /* Send any post-transfer QUOTE strings? */
3424   if(!status && !result && !premature && data->set.postquote)
3425     result = ftp_sendquote(conn, data->set.postquote);
3426
3427   return result;
3428 }
3429
3430 /***********************************************************************
3431  *
3432  * ftp_sendquote()
3433  *
3434  * Where a 'quote' means a list of custom commands to send to the server.
3435  * The quote list is passed as an argument.
3436  *
3437  * BLOCKING
3438  */
3439
3440 static
3441 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3442 {
3443   struct curl_slist *item;
3444   ssize_t nread;
3445   int ftpcode;
3446   CURLcode result;
3447   struct ftp_conn *ftpc = &conn->proto.ftpc;
3448   struct pingpong *pp = &ftpc->pp;
3449
3450   item = quote;
3451   while(item) {
3452     if(item->data) {
3453       char *cmd = item->data;
3454       bool acceptfail = FALSE;
3455
3456       /* if a command starts with an asterisk, which a legal FTP command never
3457          can, the command will be allowed to fail without it causing any
3458          aborts or cancels etc. It will cause libcurl to act as if the command
3459          is successful, whatever the server reponds. */
3460
3461       if(cmd[0] == '*') {
3462         cmd++;
3463         acceptfail = TRUE;
3464       }
3465
3466       PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
3467
3468       pp->response = Curl_tvnow(); /* timeout relative now */
3469
3470       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3471       if(result)
3472         return result;
3473
3474       if(!acceptfail && (ftpcode >= 400)) {
3475         failf(conn->data, "QUOT string not accepted: %s", cmd);
3476         return CURLE_QUOTE_ERROR;
3477       }
3478     }
3479
3480     item = item->next;
3481   }
3482
3483   return CURLE_OK;
3484 }
3485
3486 /***********************************************************************
3487  *
3488  * ftp_need_type()
3489  *
3490  * Returns TRUE if we in the current situation should send TYPE
3491  */
3492 static int ftp_need_type(struct connectdata *conn,
3493                          bool ascii_wanted)
3494 {
3495   return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3496 }
3497
3498 /***********************************************************************
3499  *
3500  * ftp_nb_type()
3501  *
3502  * Set TYPE. We only deal with ASCII or BINARY so this function
3503  * sets one of them.
3504  * If the transfer type is not sent, simulate on OK response in newstate
3505  */
3506 static CURLcode ftp_nb_type(struct connectdata *conn,
3507                             bool ascii, ftpstate newstate)
3508 {
3509   struct ftp_conn *ftpc = &conn->proto.ftpc;
3510   CURLcode result;
3511   char want = (char)(ascii?'A':'I');
3512
3513   if(ftpc->transfertype == want) {
3514     state(conn, newstate);
3515     return ftp_state_type_resp(conn, 200, newstate);
3516   }
3517
3518   PPSENDF(&ftpc->pp, "TYPE %c", want);
3519   state(conn, newstate);
3520
3521   /* keep track of our current transfer type */
3522   ftpc->transfertype = want;
3523   return CURLE_OK;
3524 }
3525
3526 /***************************************************************************
3527  *
3528  * ftp_pasv_verbose()
3529  *
3530  * This function only outputs some informationals about this second connection
3531  * when we've issued a PASV command before and thus we have connected to a
3532  * possibly new IP address.
3533  *
3534  */
3535 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3536 static void
3537 ftp_pasv_verbose(struct connectdata *conn,
3538                  Curl_addrinfo *ai,
3539                  char *newhost, /* ascii version */
3540                  int port)
3541 {
3542   char buf[256];
3543   Curl_printable_address(ai, buf, sizeof(buf));
3544   infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3545 }
3546 #endif
3547
3548 /*
3549   Check if this is a range download, and if so, set the internal variables
3550   properly.
3551  */
3552
3553 static CURLcode ftp_range(struct connectdata *conn)
3554 {
3555   curl_off_t from, to;
3556   char *ptr;
3557   char *ptr2;
3558   struct SessionHandle *data = conn->data;
3559   struct ftp_conn *ftpc = &conn->proto.ftpc;
3560
3561   if(data->state.use_range && data->state.range) {
3562     from=curlx_strtoofft(data->state.range, &ptr, 0);
3563     while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3564       ptr++;
3565     to=curlx_strtoofft(ptr, &ptr2, 0);
3566     if(ptr == ptr2) {
3567       /* we didn't get any digit */
3568       to=-1;
3569     }
3570     if((-1 == to) && (from>=0)) {
3571       /* X - */
3572       data->state.resume_from = from;
3573       DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
3574                    " to end of file\n", from));
3575     }
3576     else if(from < 0) {
3577       /* -Y */
3578       data->req.maxdownload = -from;
3579       data->state.resume_from = from;
3580       DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
3581                    " bytes\n", -from));
3582     }
3583     else {
3584       /* X-Y */
3585       data->req.maxdownload = (to-from)+1; /* include last byte */
3586       data->state.resume_from = from;
3587       DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
3588                    " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
3589                    from, data->req.maxdownload));
3590     }
3591     DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
3592                  " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
3593                  CURL_FORMAT_CURL_OFF_T " bytes\n",
3594                  from, to, data->req.maxdownload));
3595     ftpc->dont_check = TRUE; /* dont check for successful transfer */
3596   }
3597   else
3598     data->req.maxdownload = -1;
3599   return CURLE_OK;
3600 }
3601
3602
3603 /*
3604  * ftp_do_more()
3605  *
3606  * This function shall be called when the second FTP (data) connection is
3607  * connected.
3608  *
3609  * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3610  * (which basically is only for when PASV is being sent to retry a failed
3611  * EPSV).
3612  */
3613
3614 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
3615 {
3616   struct SessionHandle *data=conn->data;
3617   struct ftp_conn *ftpc = &conn->proto.ftpc;
3618   CURLcode result = CURLE_OK;
3619   bool connected = FALSE;
3620   bool complete = FALSE;
3621
3622   /* the ftp struct is inited in ftp_connect() */
3623   struct FTP *ftp = data->req.protop;
3624
3625   /* if the second connection isn't done yet, wait for it */
3626   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3627     if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
3628       /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3629          aren't used so we blank their arguments. TODO: make this nicer */
3630       result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
3631
3632       return result;
3633     }
3634
3635     result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3636
3637     /* Ready to do more? */
3638     if(connected) {
3639       DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3640       if(conn->bits.proxy) {
3641         infof(data, "Connection to proxy confirmed\n");
3642         result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected);
3643       }
3644     }
3645     else {
3646       if(result && (ftpc->count1 == 0)) {
3647         *completep = -1; /* go back to DOING please */
3648         /* this is a EPSV connect failing, try PASV instead */
3649         return ftp_epsv_disable(conn);
3650       }
3651       return result;
3652     }
3653   }
3654
3655   if(ftpc->state) {
3656     /* already in a state so skip the intial commands.
3657        They are only done to kickstart the do_more state */
3658     result = ftp_multi_statemach(conn, &complete);
3659
3660     *completep = (int)complete;
3661
3662     /* if we got an error or if we don't wait for a data connection return
3663        immediately */
3664     if(result || (ftpc->wait_data_conn != TRUE))
3665       return result;
3666
3667     if(ftpc->wait_data_conn)
3668       /* if we reach the end of the FTP state machine here, *complete will be
3669          TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3670          the data connection and therefore we're not actually complete */
3671       *completep = 0;
3672   }
3673
3674   if(ftp->transfer <= FTPTRANSFER_INFO) {
3675     /* a transfer is about to take place, or if not a file name was given
3676        so we'll do a SIZE on it later and then we need the right TYPE first */
3677
3678     if(ftpc->wait_data_conn == TRUE) {
3679       bool serv_conned;
3680
3681       result = ReceivedServerConnect(conn, &serv_conned);
3682       if(result)
3683         return result; /* Failed to accept data connection */
3684
3685       if(serv_conned) {
3686         /* It looks data connection is established */
3687         result = AcceptServerConnect(conn);
3688         ftpc->wait_data_conn = FALSE;
3689         if(!result)
3690           result = InitiateTransfer(conn);
3691
3692         if(result)
3693           return result;
3694
3695         *completep = 1; /* this state is now complete when the server has
3696                            connected back to us */
3697       }
3698     }
3699     else if(data->set.upload) {
3700       result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3701       if(result)
3702         return result;
3703
3704       result = ftp_multi_statemach(conn, &complete);
3705       *completep = (int)complete;
3706     }
3707     else {
3708       /* download */
3709       ftp->downloadsize = -1; /* unknown as of yet */
3710
3711       result = ftp_range(conn);
3712       if(result)
3713         ;
3714       else if(data->set.ftp_list_only || !ftpc->file) {
3715         /* The specified path ends with a slash, and therefore we think this
3716            is a directory that is requested, use LIST. But before that we
3717            need to set ASCII transfer mode. */
3718
3719         /* But only if a body transfer was requested. */
3720         if(ftp->transfer == FTPTRANSFER_BODY) {
3721           result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3722           if(result)
3723             return result;
3724         }
3725         /* otherwise just fall through */
3726       }
3727       else {
3728         result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3729         if(result)
3730           return result;
3731       }
3732
3733       result = ftp_multi_statemach(conn, &complete);
3734       *completep = (int)complete;
3735     }
3736     return result;
3737   }
3738
3739   if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
3740     /* no data to transfer. FIX: it feels like a kludge to have this here
3741        too! */
3742     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3743
3744   if(!ftpc->wait_data_conn) {
3745     /* no waiting for the data connection so this is now complete */
3746     *completep = 1;
3747     DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3748   }
3749
3750   return result;
3751 }
3752
3753
3754
3755 /***********************************************************************
3756  *
3757  * ftp_perform()
3758  *
3759  * This is the actual DO function for FTP. Get a file/directory according to
3760  * the options previously setup.
3761  */
3762
3763 static
3764 CURLcode ftp_perform(struct connectdata *conn,
3765                      bool *connected,  /* connect status after PASV / PORT */
3766                      bool *dophase_done)
3767 {
3768   /* this is FTP and no proxy */
3769   CURLcode result=CURLE_OK;
3770
3771   DEBUGF(infof(conn->data, "DO phase starts\n"));
3772
3773   if(conn->data->set.opt_no_body) {
3774     /* requested no body means no transfer... */
3775     struct FTP *ftp = conn->data->req.protop;
3776     ftp->transfer = FTPTRANSFER_INFO;
3777   }
3778
3779   *dophase_done = FALSE; /* not done yet */
3780
3781   /* start the first command in the DO phase */
3782   result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3783   if(result)
3784     return result;
3785
3786   /* run the state-machine */
3787   result = ftp_multi_statemach(conn, dophase_done);
3788
3789   *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3790
3791   infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
3792
3793   if(*dophase_done)
3794     DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3795
3796   return result;
3797 }
3798
3799 static void wc_data_dtor(void *ptr)
3800 {
3801   struct ftp_wc_tmpdata *tmp = ptr;
3802   if(tmp)
3803     Curl_ftp_parselist_data_free(&tmp->parser);
3804   Curl_safefree(tmp);
3805 }
3806
3807 static CURLcode init_wc_data(struct connectdata *conn)
3808 {
3809   char *last_slash;
3810   char *path = conn->data->state.path;
3811   struct WildcardData *wildcard = &(conn->data->wildcard);
3812   CURLcode ret = CURLE_OK;
3813   struct ftp_wc_tmpdata *ftp_tmp;
3814
3815   last_slash = strrchr(conn->data->state.path, '/');
3816   if(last_slash) {
3817     last_slash++;
3818     if(last_slash[0] == '\0') {
3819       wildcard->state = CURLWC_CLEAN;
3820       ret = ftp_parse_url_path(conn);
3821       return ret;
3822     }
3823     else {
3824       wildcard->pattern = strdup(last_slash);
3825       if(!wildcard->pattern)
3826         return CURLE_OUT_OF_MEMORY;
3827       last_slash[0] = '\0'; /* cut file from path */
3828     }
3829   }
3830   else { /* there is only 'wildcard pattern' or nothing */
3831     if(path[0]) {
3832       wildcard->pattern = strdup(path);
3833       if(!wildcard->pattern)
3834         return CURLE_OUT_OF_MEMORY;
3835       path[0] = '\0';
3836     }
3837     else { /* only list */
3838       wildcard->state = CURLWC_CLEAN;
3839       ret = ftp_parse_url_path(conn);
3840       return ret;
3841     }
3842   }
3843
3844   /* program continues only if URL is not ending with slash, allocate needed
3845      resources for wildcard transfer */
3846
3847   /* allocate ftp protocol specific temporary wildcard data */
3848   ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3849   if(!ftp_tmp) {
3850     Curl_safefree(wildcard->pattern);
3851     return CURLE_OUT_OF_MEMORY;
3852   }
3853
3854   /* INITIALIZE parselist structure */
3855   ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3856   if(!ftp_tmp->parser) {
3857     Curl_safefree(wildcard->pattern);
3858     Curl_safefree(ftp_tmp);
3859     return CURLE_OUT_OF_MEMORY;
3860   }
3861
3862   wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3863   wildcard->tmp_dtor = wc_data_dtor;
3864
3865   /* wildcard does not support NOCWD option (assert it?) */
3866   if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3867     conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3868
3869   /* try to parse ftp url */
3870   ret = ftp_parse_url_path(conn);
3871   if(ret) {
3872     Curl_safefree(wildcard->pattern);
3873     wildcard->tmp_dtor(wildcard->tmp);
3874     wildcard->tmp_dtor = ZERO_NULL;
3875     wildcard->tmp = NULL;
3876     return ret;
3877   }
3878
3879   wildcard->path = strdup(conn->data->state.path);
3880   if(!wildcard->path) {
3881     Curl_safefree(wildcard->pattern);
3882     wildcard->tmp_dtor(wildcard->tmp);
3883     wildcard->tmp_dtor = ZERO_NULL;
3884     wildcard->tmp = NULL;
3885     return CURLE_OUT_OF_MEMORY;
3886   }
3887
3888   /* backup old write_function */
3889   ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3890   /* parsing write function */
3891   conn->data->set.fwrite_func = Curl_ftp_parselist;
3892   /* backup old file descriptor */
3893   ftp_tmp->backup.file_descriptor = conn->data->set.out;
3894   /* let the writefunc callback know what curl pointer is working with */
3895   conn->data->set.out = conn;
3896
3897   infof(conn->data, "Wildcard - Parsing started\n");
3898   return CURLE_OK;
3899 }
3900
3901 /* This is called recursively */
3902 static CURLcode wc_statemach(struct connectdata *conn)
3903 {
3904   struct WildcardData * const wildcard = &(conn->data->wildcard);
3905   CURLcode ret = CURLE_OK;
3906
3907   switch (wildcard->state) {
3908   case CURLWC_INIT:
3909     ret = init_wc_data(conn);
3910     if(wildcard->state == CURLWC_CLEAN)
3911       /* only listing! */
3912       break;
3913     else
3914       wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING;
3915     break;
3916
3917   case CURLWC_MATCHING: {
3918     /* In this state is LIST response successfully parsed, so lets restore
3919        previous WRITEFUNCTION callback and WRITEDATA pointer */
3920     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3921     conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3922     conn->data->set.out = ftp_tmp->backup.file_descriptor;
3923     ftp_tmp->backup.write_function = ZERO_NULL;
3924     ftp_tmp->backup.file_descriptor = NULL;
3925     wildcard->state = CURLWC_DOWNLOADING;
3926
3927     if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3928       /* error found in LIST parsing */
3929       wildcard->state = CURLWC_CLEAN;
3930       return wc_statemach(conn);
3931     }
3932     else if(wildcard->filelist->size == 0) {
3933       /* no corresponding file */
3934       wildcard->state = CURLWC_CLEAN;
3935       return CURLE_REMOTE_FILE_NOT_FOUND;
3936     }
3937     return wc_statemach(conn);
3938   }
3939
3940   case CURLWC_DOWNLOADING: {
3941     /* filelist has at least one file, lets get first one */
3942     struct ftp_conn *ftpc = &conn->proto.ftpc;
3943     struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3944
3945     char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3946     if(!tmp_path)
3947       return CURLE_OUT_OF_MEMORY;
3948
3949     /* switch default "state.pathbuffer" and tmp_path, good to see
3950        ftp_parse_url_path function to understand this trick */
3951     Curl_safefree(conn->data->state.pathbuffer);
3952     conn->data->state.pathbuffer = tmp_path;
3953     conn->data->state.path = tmp_path;
3954
3955     infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3956     if(conn->data->set.chunk_bgn) {
3957       long userresponse = conn->data->set.chunk_bgn(
3958           finfo, wildcard->customptr, (int)wildcard->filelist->size);
3959       switch(userresponse) {
3960       case CURL_CHUNK_BGN_FUNC_SKIP:
3961         infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3962               finfo->filename);
3963         wildcard->state = CURLWC_SKIP;
3964         return wc_statemach(conn);
3965       case CURL_CHUNK_BGN_FUNC_FAIL:
3966         return CURLE_CHUNK_FAILED;
3967       }
3968     }
3969
3970     if(finfo->filetype != CURLFILETYPE_FILE) {
3971       wildcard->state = CURLWC_SKIP;
3972       return wc_statemach(conn);
3973     }
3974
3975     if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3976       ftpc->known_filesize = finfo->size;
3977
3978     ret = ftp_parse_url_path(conn);
3979     if(ret) {
3980       return ret;
3981     }
3982
3983     /* we don't need the Curl_fileinfo of first file anymore */
3984     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3985
3986     if(wildcard->filelist->size == 0) { /* remains only one file to down. */
3987       wildcard->state = CURLWC_CLEAN;
3988       /* after that will be ftp_do called once again and no transfer
3989          will be done because of CURLWC_CLEAN state */
3990       return CURLE_OK;
3991     }
3992   } break;
3993
3994   case CURLWC_SKIP: {
3995     if(conn->data->set.chunk_end)
3996       conn->data->set.chunk_end(conn->data->wildcard.customptr);
3997     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3998     wildcard->state = (wildcard->filelist->size == 0) ?
3999                       CURLWC_CLEAN : CURLWC_DOWNLOADING;
4000     return wc_statemach(conn);
4001   }
4002
4003   case CURLWC_CLEAN: {
4004     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
4005     ret = CURLE_OK;
4006     if(ftp_tmp) {
4007       ret = Curl_ftp_parselist_geterror(ftp_tmp->parser);
4008     }
4009     wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE;
4010   } break;
4011
4012   case CURLWC_DONE:
4013   case CURLWC_ERROR:
4014     break;
4015   }
4016
4017   return ret;
4018 }
4019
4020 /***********************************************************************
4021  *
4022  * ftp_do()
4023  *
4024  * This function is registered as 'curl_do' function. It decodes the path
4025  * parts etc as a wrapper to the actual DO function (ftp_perform).
4026  *
4027  * The input argument is already checked for validity.
4028  */
4029 static CURLcode ftp_do(struct connectdata *conn, bool *done)
4030 {
4031   CURLcode retcode = CURLE_OK;
4032   struct ftp_conn *ftpc = &conn->proto.ftpc;
4033
4034   *done = FALSE; /* default to false */
4035   ftpc->wait_data_conn = FALSE; /* default to no such wait */
4036
4037   if(conn->data->set.wildcardmatch) {
4038     retcode = wc_statemach(conn);
4039     if(conn->data->wildcard.state == CURLWC_SKIP ||
4040       conn->data->wildcard.state == CURLWC_DONE) {
4041       /* do not call ftp_regular_transfer */
4042       return CURLE_OK;
4043     }
4044     if(retcode) /* error, loop or skipping the file */
4045       return retcode;
4046   }
4047   else { /* no wildcard FSM needed */
4048     retcode = ftp_parse_url_path(conn);
4049     if(retcode)
4050       return retcode;
4051   }
4052
4053   retcode = ftp_regular_transfer(conn, done);
4054
4055   return retcode;
4056 }
4057
4058
4059 CURLcode Curl_ftpsendf(struct connectdata *conn,
4060                        const char *fmt, ...)
4061 {
4062   ssize_t bytes_written;
4063 #define SBUF_SIZE 1024
4064   char s[SBUF_SIZE];
4065   size_t write_len;
4066   char *sptr=s;
4067   CURLcode res = CURLE_OK;
4068 #ifdef HAVE_GSSAPI
4069   enum protection_level data_sec = conn->data_prot;
4070 #endif
4071
4072   va_list ap;
4073   va_start(ap, fmt);
4074   write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap);
4075   va_end(ap);
4076
4077   strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
4078   write_len +=2;
4079
4080   bytes_written=0;
4081
4082   res = Curl_convert_to_network(conn->data, s, write_len);
4083   /* Curl_convert_to_network calls failf if unsuccessful */
4084   if(res)
4085     return(res);
4086
4087   for(;;) {
4088 #ifdef HAVE_GSSAPI
4089     conn->data_prot = PROT_CMD;
4090 #endif
4091     res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4092                      &bytes_written);
4093 #ifdef HAVE_GSSAPI
4094     DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4095     conn->data_prot = data_sec;
4096 #endif
4097
4098     if(CURLE_OK != res)
4099       break;
4100
4101     if(conn->data->set.verbose)
4102       Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4103                  sptr, (size_t)bytes_written, conn);
4104
4105     if(bytes_written != (ssize_t)write_len) {
4106       write_len -= bytes_written;
4107       sptr += bytes_written;
4108     }
4109     else
4110       break;
4111   }
4112
4113   return res;
4114 }
4115
4116 /***********************************************************************
4117  *
4118  * ftp_quit()
4119  *
4120  * This should be called before calling sclose() on an ftp control connection
4121  * (not data connections). We should then wait for the response from the
4122  * server before returning. The calling code should then try to close the
4123  * connection.
4124  *
4125  */
4126 static CURLcode ftp_quit(struct connectdata *conn)
4127 {
4128   CURLcode result = CURLE_OK;
4129
4130   if(conn->proto.ftpc.ctl_valid) {
4131     result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
4132     if(result) {
4133       failf(conn->data, "Failure sending QUIT command: %s",
4134             curl_easy_strerror(result));
4135       conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4136       connclose(conn, "QUIT command failed"); /* mark for connection closure */
4137       state(conn, FTP_STOP);
4138       return result;
4139     }
4140
4141     state(conn, FTP_QUIT);
4142
4143     result = ftp_block_statemach(conn);
4144   }
4145
4146   return result;
4147 }
4148
4149 /***********************************************************************
4150  *
4151  * ftp_disconnect()
4152  *
4153  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4154  * resources. BLOCKING.
4155  */
4156 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4157 {
4158   struct ftp_conn *ftpc= &conn->proto.ftpc;
4159   struct pingpong *pp = &ftpc->pp;
4160
4161   /* We cannot send quit unconditionally. If this connection is stale or
4162      bad in any way, sending quit and waiting around here will make the
4163      disconnect wait in vain and cause more problems than we need to.
4164
4165      ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4166      will try to send the QUIT command, otherwise it will just return.
4167   */
4168   if(dead_connection)
4169     ftpc->ctl_valid = FALSE;
4170
4171   /* The FTP session may or may not have been allocated/setup at this point! */
4172   (void)ftp_quit(conn); /* ignore errors on the QUIT */
4173
4174   if(ftpc->entrypath) {
4175     struct SessionHandle *data = conn->data;
4176     if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4177       data->state.most_recent_ftp_entrypath = NULL;
4178     }
4179     free(ftpc->entrypath);
4180     ftpc->entrypath = NULL;
4181   }
4182
4183   freedirs(ftpc);
4184   if(ftpc->prevpath) {
4185     free(ftpc->prevpath);
4186     ftpc->prevpath = NULL;
4187   }
4188   if(ftpc->server_os) {
4189     free(ftpc->server_os);
4190     ftpc->server_os = NULL;
4191   }
4192
4193   Curl_pp_disconnect(pp);
4194
4195 #ifdef HAVE_GSSAPI
4196   Curl_sec_end(conn);
4197 #endif
4198
4199   return CURLE_OK;
4200 }
4201
4202 /***********************************************************************
4203  *
4204  * ftp_parse_url_path()
4205  *
4206  * Parse the URL path into separate path components.
4207  *
4208  */
4209 static
4210 CURLcode ftp_parse_url_path(struct connectdata *conn)
4211 {
4212   struct SessionHandle *data = conn->data;
4213   /* the ftp struct is already inited in ftp_connect() */
4214   struct FTP *ftp = data->req.protop;
4215   struct ftp_conn *ftpc = &conn->proto.ftpc;
4216   const char *slash_pos;  /* position of the first '/' char in curpos */
4217   const char *path_to_use = data->state.path;
4218   const char *cur_pos;
4219   const char *filename = NULL;
4220
4221   cur_pos = path_to_use; /* current position in path. point at the begin
4222                             of next path component */
4223
4224   ftpc->ctl_valid = FALSE;
4225   ftpc->cwdfail = FALSE;
4226
4227   switch(data->set.ftp_filemethod) {
4228   case FTPFILE_NOCWD:
4229     /* fastest, but less standard-compliant */
4230
4231     /*
4232       The best time to check whether the path is a file or directory is right
4233       here. so:
4234
4235       the first condition in the if() right here, is there just in case
4236       someone decides to set path to NULL one day
4237    */
4238     if(data->state.path &&
4239        data->state.path[0] &&
4240        (data->state.path[strlen(data->state.path) - 1] != '/') )
4241       filename = data->state.path;  /* this is a full file path */
4242       /*
4243         ftpc->file is not used anywhere other than for operations on a file.
4244         In other words, never for directory operations.
4245         So we can safely leave filename as NULL here and use it as a
4246         argument in dir/file decisions.
4247       */
4248     break;
4249
4250   case FTPFILE_SINGLECWD:
4251     /* get the last slash */
4252     if(!path_to_use[0]) {
4253       /* no dir, no file */
4254       ftpc->dirdepth = 0;
4255       break;
4256     }
4257     slash_pos=strrchr(cur_pos, '/');
4258     if(slash_pos || !*cur_pos) {
4259       size_t dirlen = slash_pos-cur_pos;
4260
4261       ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4262       if(!ftpc->dirs)
4263         return CURLE_OUT_OF_MEMORY;
4264
4265       if(!dirlen)
4266         dirlen++;
4267
4268       ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
4269                                          slash_pos ? curlx_uztosi(dirlen) : 1,
4270                                          NULL);
4271       if(!ftpc->dirs[0]) {
4272         freedirs(ftpc);
4273         return CURLE_OUT_OF_MEMORY;
4274       }
4275       ftpc->dirdepth = 1; /* we consider it to be a single dir */
4276       filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4277     }
4278     else
4279       filename = cur_pos;  /* this is a file name only */
4280     break;
4281
4282   default: /* allow pretty much anything */
4283   case FTPFILE_MULTICWD:
4284     ftpc->dirdepth = 0;
4285     ftpc->diralloc = 5; /* default dir depth to allocate */
4286     ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4287     if(!ftpc->dirs)
4288       return CURLE_OUT_OF_MEMORY;
4289
4290     /* we have a special case for listing the root dir only */
4291     if(strequal(path_to_use, "/")) {
4292       cur_pos++; /* make it point to the zero byte */
4293       ftpc->dirs[0] = strdup("/");
4294       ftpc->dirdepth++;
4295     }
4296     else {
4297       /* parse the URL path into separate path components */
4298       while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4299         /* 1 or 0 pointer offset to indicate absolute directory */
4300         ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4301                                 (ftpc->dirdepth == 0))?1:0;
4302
4303         /* seek out the next path component */
4304         if(slash_pos-cur_pos) {
4305           /* we skip empty path components, like "x//y" since the FTP command
4306              CWD requires a parameter and a non-existent parameter a) doesn't
4307              work on many servers and b) has no effect on the others. */
4308           int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
4309           ftpc->dirs[ftpc->dirdepth] =
4310             curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
4311           if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
4312             failf(data, "no memory");
4313             freedirs(ftpc);
4314             return CURLE_OUT_OF_MEMORY;
4315           }
4316           if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
4317             free(ftpc->dirs[ftpc->dirdepth]);
4318             freedirs(ftpc);
4319             return CURLE_URL_MALFORMAT;
4320           }
4321         }
4322         else {
4323           cur_pos = slash_pos + 1; /* jump to the rest of the string */
4324           if(!ftpc->dirdepth) {
4325             /* path starts with a slash, add that as a directory */
4326             ftpc->dirs[ftpc->dirdepth] = strdup("/");
4327             if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
4328               failf(data, "no memory");
4329               freedirs(ftpc);
4330               return CURLE_OUT_OF_MEMORY;
4331             }
4332           }
4333           continue;
4334         }
4335
4336         cur_pos = slash_pos + 1; /* jump to the rest of the string */
4337         if(++ftpc->dirdepth >= ftpc->diralloc) {
4338           /* enlarge array */
4339           char **bigger;
4340           ftpc->diralloc *= 2; /* double the size each time */
4341           bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4342           if(!bigger) {
4343             freedirs(ftpc);
4344             return CURLE_OUT_OF_MEMORY;
4345           }
4346           ftpc->dirs = bigger;
4347         }
4348       }
4349     }
4350     filename = cur_pos;  /* the rest is the file name */
4351     break;
4352   } /* switch */
4353
4354   if(filename && *filename) {
4355     ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
4356     if(NULL == ftpc->file) {
4357       freedirs(ftpc);
4358       failf(data, "no memory");
4359       return CURLE_OUT_OF_MEMORY;
4360     }
4361     if(isBadFtpString(ftpc->file)) {
4362       freedirs(ftpc);
4363       return CURLE_URL_MALFORMAT;
4364     }
4365   }
4366   else
4367     ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4368                        pointer */
4369
4370   if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4371     /* We need a file name when uploading. Return error! */
4372     failf(data, "Uploading to a URL without a file name!");
4373     return CURLE_URL_MALFORMAT;
4374   }
4375
4376   ftpc->cwddone = FALSE; /* default to not done */
4377
4378   if(ftpc->prevpath) {
4379     /* prevpath is "raw" so we convert the input path before we compare the
4380        strings */
4381     int dlen;
4382     char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4383     if(!path) {
4384       freedirs(ftpc);
4385       return CURLE_OUT_OF_MEMORY;
4386     }
4387
4388     dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
4389     if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
4390        strnequal(path, ftpc->prevpath, dlen)) {
4391       infof(data, "Request has same path as previous transfer\n");
4392       ftpc->cwddone = TRUE;
4393     }
4394     free(path);
4395   }
4396
4397   return CURLE_OK;
4398 }
4399
4400 /* call this when the DO phase has completed */
4401 static CURLcode ftp_dophase_done(struct connectdata *conn,
4402                                  bool connected)
4403 {
4404   struct FTP *ftp = conn->data->req.protop;
4405   struct ftp_conn *ftpc = &conn->proto.ftpc;
4406
4407   if(connected) {
4408     int completed;
4409     CURLcode result = ftp_do_more(conn, &completed);
4410
4411     if(result) {
4412       if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
4413         /* close the second socket if it was created already */
4414         Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
4415         conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4416       }
4417       return result;
4418     }
4419   }
4420
4421   if(ftp->transfer != FTPTRANSFER_BODY)
4422     /* no data to transfer */
4423     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4424   else if(!connected)
4425     /* since we didn't connect now, we want do_more to get called */
4426     conn->bits.do_more = TRUE;
4427
4428   ftpc->ctl_valid = TRUE; /* seems good */
4429
4430   return CURLE_OK;
4431 }
4432
4433 /* called from multi.c while DOing */
4434 static CURLcode ftp_doing(struct connectdata *conn,
4435                           bool *dophase_done)
4436 {
4437   CURLcode result = ftp_multi_statemach(conn, dophase_done);
4438
4439   if(result)
4440     DEBUGF(infof(conn->data, "DO phase failed\n"));
4441   else if(*dophase_done) {
4442     result = ftp_dophase_done(conn, FALSE /* not connected */);
4443
4444     DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4445   }
4446   return result;
4447 }
4448
4449 /***********************************************************************
4450  *
4451  * ftp_regular_transfer()
4452  *
4453  * The input argument is already checked for validity.
4454  *
4455  * Performs all commands done before a regular transfer between a local and a
4456  * remote host.
4457  *
4458  * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4459  * ftp_done() function without finding any major problem.
4460  */
4461 static
4462 CURLcode ftp_regular_transfer(struct connectdata *conn,
4463                               bool *dophase_done)
4464 {
4465   CURLcode result=CURLE_OK;
4466   bool connected=FALSE;
4467   struct SessionHandle *data = conn->data;
4468   struct ftp_conn *ftpc = &conn->proto.ftpc;
4469   data->req.size = -1; /* make sure this is unknown at this point */
4470
4471   Curl_pgrsSetUploadCounter(data, 0);
4472   Curl_pgrsSetDownloadCounter(data, 0);
4473   Curl_pgrsSetUploadSize(data, 0);
4474   Curl_pgrsSetDownloadSize(data, 0);
4475
4476   ftpc->ctl_valid = TRUE; /* starts good */
4477
4478   result = ftp_perform(conn,
4479                        &connected, /* have we connected after PASV/PORT */
4480                        dophase_done); /* all commands in the DO-phase done? */
4481
4482   if(CURLE_OK == result) {
4483
4484     if(!*dophase_done)
4485       /* the DO phase has not completed yet */
4486       return CURLE_OK;
4487
4488     result = ftp_dophase_done(conn, connected);
4489
4490     if(result)
4491       return result;
4492   }
4493   else
4494     freedirs(ftpc);
4495
4496   return result;
4497 }
4498
4499 static CURLcode ftp_setup_connection(struct connectdata *conn)
4500 {
4501   struct SessionHandle *data = conn->data;
4502   char *type;
4503   char command;
4504   struct FTP *ftp;
4505
4506   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4507     /* Unless we have asked to tunnel ftp operations through the proxy, we
4508        switch and use HTTP operations only */
4509 #ifndef CURL_DISABLE_HTTP
4510     if(conn->handler == &Curl_handler_ftp)
4511       conn->handler = &Curl_handler_ftp_proxy;
4512     else {
4513 #ifdef USE_SSL
4514       conn->handler = &Curl_handler_ftps_proxy;
4515 #else
4516       failf(data, "FTPS not supported!");
4517       return CURLE_UNSUPPORTED_PROTOCOL;
4518 #endif
4519     }
4520     /* set it up as a HTTP connection instead */
4521     return conn->handler->setup_connection(conn);
4522 #else
4523     failf(data, "FTP over http proxy requires HTTP support built-in!");
4524     return CURLE_UNSUPPORTED_PROTOCOL;
4525 #endif
4526   }
4527
4528   conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
4529   if(NULL == ftp)
4530     return CURLE_OUT_OF_MEMORY;
4531
4532   data->state.path++;   /* don't include the initial slash */
4533   data->state.slash_removed = TRUE; /* we've skipped the slash */
4534
4535   /* FTP URLs support an extension like ";type=<typecode>" that
4536    * we'll try to get now! */
4537   type = strstr(data->state.path, ";type=");
4538
4539   if(!type)
4540     type = strstr(conn->host.rawalloc, ";type=");
4541
4542   if(type) {
4543     *type = 0;                     /* it was in the middle of the hostname */
4544     command = Curl_raw_toupper(type[6]);
4545     conn->bits.type_set = TRUE;
4546
4547     switch (command) {
4548     case 'A': /* ASCII mode */
4549       data->set.prefer_ascii = TRUE;
4550       break;
4551
4552     case 'D': /* directory mode */
4553       data->set.ftp_list_only = TRUE;
4554       break;
4555
4556     case 'I': /* binary mode */
4557     default:
4558       /* switch off ASCII */
4559       data->set.prefer_ascii = FALSE;
4560       break;
4561     }
4562   }
4563
4564   /* get some initial data into the ftp struct */
4565   ftp->bytecountp = &conn->data->req.bytecount;
4566   ftp->transfer = FTPTRANSFER_BODY;
4567   ftp->downloadsize = 0;
4568
4569   /* No need to duplicate user+password, the connectdata struct won't change
4570      during a session, but we re-init them here since on subsequent inits
4571      since the conn struct may have changed or been replaced.
4572   */
4573   ftp->user = conn->user;
4574   ftp->passwd = conn->passwd;
4575   if(isBadFtpString(ftp->user))
4576     return CURLE_URL_MALFORMAT;
4577   if(isBadFtpString(ftp->passwd))
4578     return CURLE_URL_MALFORMAT;
4579
4580   conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4581
4582   return CURLE_OK;
4583 }
4584
4585 #endif /* CURL_DISABLE_FTP */