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