Revert "Update to 7.44.0"
[platform/upstream/curl.git] / lib / ftp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2015, 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   Curl_safefree(ftpc->file);
298
299   /* no longer of any use */
300   Curl_safefree(ftpc->newhost);
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
1819   if(conn->bits.ipv6) {
1820     /* We can't disable EPSV when doing IPv6, so this is instead a fail */
1821     failf(conn->data, "Failed EPSV attempt, exiting\n");
1822     return CURLE_FTP_WEIRD_SERVER_REPLY;
1823   }
1824
1825   infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
1826   /* disable it for next transfer */
1827   conn->bits.ftp_use_epsv = FALSE;
1828   conn->data->state.errorbuf = FALSE; /* allow error message to get
1829                                          rewritten */
1830   PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
1831   conn->proto.ftpc.count1++;
1832   /* remain in/go to the FTP_PASV state */
1833   state(conn, FTP_PASV);
1834   return result;
1835 }
1836
1837 /*
1838  * Perform the necessary magic that needs to be done once the TCP connection
1839  * to the proxy has completed.
1840  */
1841 static CURLcode proxy_magic(struct connectdata *conn,
1842                             char *newhost, unsigned short newport,
1843                             bool *magicdone)
1844 {
1845   CURLcode result = CURLE_OK;
1846   struct SessionHandle *data = conn->data;
1847
1848 #if defined(CURL_DISABLE_PROXY)
1849   (void) newhost;
1850   (void) newport;
1851 #endif
1852
1853   *magicdone = FALSE;
1854
1855   switch(conn->proxytype) {
1856   case CURLPROXY_SOCKS5:
1857   case CURLPROXY_SOCKS5_HOSTNAME:
1858     result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost,
1859                          newport, SECONDARYSOCKET, conn);
1860     *magicdone = TRUE;
1861     break;
1862   case CURLPROXY_SOCKS4:
1863     result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1864                          SECONDARYSOCKET, conn, FALSE);
1865     *magicdone = TRUE;
1866     break;
1867   case CURLPROXY_SOCKS4A:
1868     result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
1869                          SECONDARYSOCKET, conn, TRUE);
1870     *magicdone = TRUE;
1871     break;
1872   case CURLPROXY_HTTP:
1873   case CURLPROXY_HTTP_1_0:
1874     /* do nothing here. handled later. */
1875     break;
1876   default:
1877     failf(data, "unknown proxytype option given");
1878     result = CURLE_COULDNT_CONNECT;
1879     break;
1880   }
1881
1882   if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1883     /* BLOCKING */
1884     /* We want "seamless" FTP operations through HTTP proxy tunnel */
1885
1886     /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
1887      * member conn->proto.http; we want FTP through HTTP and we have to
1888      * change the member temporarily for connecting to the HTTP proxy. After
1889      * Curl_proxyCONNECT we have to set back the member to the original
1890      * struct FTP pointer
1891      */
1892     struct HTTP http_proxy;
1893     struct FTP *ftp_save = data->req.protop;
1894     memset(&http_proxy, 0, sizeof(http_proxy));
1895     data->req.protop = &http_proxy;
1896
1897     result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
1898
1899     data->req.protop = ftp_save;
1900
1901     if(result)
1902       return result;
1903
1904     if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
1905       /* the CONNECT procedure is not complete, the tunnel is not yet up */
1906       state(conn, FTP_STOP); /* this phase is completed */
1907       return result;
1908     }
1909     else
1910       *magicdone = TRUE;
1911   }
1912
1913   return result;
1914 }
1915
1916 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1917                                     int ftpcode)
1918 {
1919   struct ftp_conn *ftpc = &conn->proto.ftpc;
1920   CURLcode result;
1921   struct SessionHandle *data=conn->data;
1922   struct Curl_dns_entry *addr=NULL;
1923   int rc;
1924   unsigned short connectport; /* the local port connect() should use! */
1925   char *str=&data->state.buffer[4];  /* start on the first letter */
1926
1927   /* if we come here again, make sure the former name is cleared */
1928   Curl_safefree(ftpc->newhost);
1929
1930   if((ftpc->count1 == 0) &&
1931      (ftpcode == 229)) {
1932     /* positive EPSV response */
1933     char *ptr = strchr(str, '(');
1934     if(ptr) {
1935       unsigned int num;
1936       char separator[4];
1937       ptr++;
1938       if(5  == sscanf(ptr, "%c%c%c%u%c",
1939                       &separator[0],
1940                       &separator[1],
1941                       &separator[2],
1942                       &num,
1943                       &separator[3])) {
1944         const char sep1 = separator[0];
1945         int i;
1946
1947         /* The four separators should be identical, or else this is an oddly
1948            formatted reply and we bail out immediately. */
1949         for(i=1; i<4; i++) {
1950           if(separator[i] != sep1) {
1951             ptr=NULL; /* set to NULL to signal error */
1952             break;
1953           }
1954         }
1955         if(num > 0xffff) {
1956           failf(data, "Illegal port number in EPSV reply");
1957           return CURLE_FTP_WEIRD_PASV_REPLY;
1958         }
1959         if(ptr) {
1960           ftpc->newport = (unsigned short)(num & 0xffff);
1961
1962           /* use the original host name again */
1963           ftpc->newhost = strdup(conn->host.name);
1964           if(!ftpc->newhost)
1965             return CURLE_OUT_OF_MEMORY;
1966         }
1967       }
1968       else
1969         ptr=NULL;
1970     }
1971     if(!ptr) {
1972       failf(data, "Weirdly formatted EPSV reply");
1973       return CURLE_FTP_WEIRD_PASV_REPLY;
1974     }
1975   }
1976   else if((ftpc->count1 == 1) &&
1977           (ftpcode == 227)) {
1978     /* positive PASV response */
1979     int ip[4];
1980     int port[2];
1981
1982     /*
1983      * Scan for a sequence of six comma-separated numbers and use them as
1984      * IP+port indicators.
1985      *
1986      * Found reply-strings include:
1987      * "227 Entering Passive Mode (127,0,0,1,4,51)"
1988      * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1989      * "227 Entering passive mode. 127,0,0,1,4,51"
1990      */
1991     while(*str) {
1992       if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1993                       &ip[0], &ip[1], &ip[2], &ip[3],
1994                       &port[0], &port[1]))
1995         break;
1996       str++;
1997     }
1998
1999     if(!*str) {
2000       failf(data, "Couldn't interpret the 227-response");
2001       return CURLE_FTP_WEIRD_227_FORMAT;
2002     }
2003
2004     /* we got OK from server */
2005     if(data->set.ftp_skip_ip) {
2006       /* told to ignore the remotely given IP but instead use the host we used
2007          for the control connection */
2008       infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
2009             ip[0], ip[1], ip[2], ip[3],
2010             conn->host.name);
2011
2012       /* use the original host name again */
2013       ftpc->newhost = strdup(conn->host.name);
2014     }
2015     else
2016       ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
2017
2018     if(!ftpc->newhost)
2019       return CURLE_OUT_OF_MEMORY;
2020
2021     ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
2022   }
2023   else if(ftpc->count1 == 0) {
2024     /* EPSV failed, move on to PASV */
2025     return ftp_epsv_disable(conn);
2026   }
2027   else {
2028     failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
2029     return CURLE_FTP_WEIRD_PASV_REPLY;
2030   }
2031
2032   if(conn->bits.proxy) {
2033     /*
2034      * This connection uses a proxy and we need to connect to the proxy again
2035      * here. We don't want to rely on a former host lookup that might've
2036      * expired now, instead we remake the lookup here and now!
2037      */
2038     rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
2039     if(rc == CURLRESOLV_PENDING)
2040       /* BLOCKING, ignores the return code but 'addr' will be NULL in
2041          case of failure */
2042       (void)Curl_resolver_wait_resolv(conn, &addr);
2043
2044     connectport =
2045       (unsigned short)conn->port; /* we connect to the proxy's port */
2046
2047     if(!addr) {
2048       failf(data, "Can't resolve proxy host %s:%hu",
2049             conn->proxy.name, connectport);
2050       return CURLE_FTP_CANT_GET_HOST;
2051     }
2052   }
2053   else {
2054     /* normal, direct, ftp connection */
2055     rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
2056     if(rc == CURLRESOLV_PENDING)
2057       /* BLOCKING */
2058       (void)Curl_resolver_wait_resolv(conn, &addr);
2059
2060     connectport = ftpc->newport; /* we connect to the remote port */
2061
2062     if(!addr) {
2063       failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
2064       return CURLE_FTP_CANT_GET_HOST;
2065     }
2066   }
2067
2068   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
2069   result = Curl_connecthost(conn, addr);
2070
2071   Curl_resolv_unlock(data, addr); /* we're done using this address */
2072
2073   if(result) {
2074     if(ftpc->count1 == 0 && ftpcode == 229)
2075       return ftp_epsv_disable(conn);
2076
2077     return result;
2078   }
2079
2080
2081   /*
2082    * When this is used from the multi interface, this might've returned with
2083    * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
2084    * connect to connect.
2085    */
2086
2087   if(data->set.verbose)
2088     /* this just dumps information about this second connection */
2089     ftp_pasv_verbose(conn, conn->ip_addr, ftpc->newhost, connectport);
2090
2091   conn->bits.do_more = TRUE;
2092   state(conn, FTP_STOP); /* this phase is completed */
2093
2094   return result;
2095 }
2096
2097 static CURLcode ftp_state_port_resp(struct connectdata *conn,
2098                                     int ftpcode)
2099 {
2100   struct SessionHandle *data = conn->data;
2101   struct ftp_conn *ftpc = &conn->proto.ftpc;
2102   ftpport fcmd = (ftpport)ftpc->count1;
2103   CURLcode result = CURLE_OK;
2104
2105   if(ftpcode != 200) {
2106     /* the command failed */
2107
2108     if(EPRT == fcmd) {
2109       infof(data, "disabling EPRT usage\n");
2110       conn->bits.ftp_use_eprt = FALSE;
2111     }
2112     fcmd++;
2113
2114     if(fcmd == DONE) {
2115       failf(data, "Failed to do PORT");
2116       result = CURLE_FTP_PORT_FAILED;
2117     }
2118     else
2119       /* try next */
2120       result = ftp_state_use_port(conn, fcmd);
2121   }
2122   else {
2123     infof(data, "Connect data stream actively\n");
2124     state(conn, FTP_STOP); /* end of DO phase */
2125     result = ftp_dophase_done(conn, FALSE);
2126   }
2127
2128   return result;
2129 }
2130
2131 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
2132                                     int ftpcode)
2133 {
2134   CURLcode result = CURLE_OK;
2135   struct SessionHandle *data=conn->data;
2136   struct FTP *ftp = data->req.protop;
2137   struct ftp_conn *ftpc = &conn->proto.ftpc;
2138
2139   switch(ftpcode) {
2140   case 213:
2141     {
2142       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
2143          last .sss part is optional and means fractions of a second */
2144       int year, month, day, hour, minute, second;
2145       char *buf = data->state.buffer;
2146       if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
2147                      &year, &month, &day, &hour, &minute, &second)) {
2148         /* we have a time, reformat it */
2149         time_t secs=time(NULL);
2150         /* using the good old yacc/bison yuck */
2151         snprintf(buf, sizeof(conn->data->state.buffer),
2152                  "%04d%02d%02d %02d:%02d:%02d GMT",
2153                  year, month, day, hour, minute, second);
2154         /* now, convert this into a time() value: */
2155         data->info.filetime = (long)curl_getdate(buf, &secs);
2156       }
2157
2158 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2159       /* If we asked for a time of the file and we actually got one as well,
2160          we "emulate" a HTTP-style header in our output. */
2161
2162       if(data->set.opt_no_body &&
2163          ftpc->file &&
2164          data->set.get_filetime &&
2165          (data->info.filetime>=0) ) {
2166         time_t filetime = (time_t)data->info.filetime;
2167         struct tm buffer;
2168         const struct tm *tm = &buffer;
2169
2170         result = Curl_gmtime(filetime, &buffer);
2171         if(result)
2172           return result;
2173
2174         /* format: "Tue, 15 Nov 1994 12:45:26" */
2175         snprintf(buf, BUFSIZE-1,
2176                  "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2177                  Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2178                  tm->tm_mday,
2179                  Curl_month[tm->tm_mon],
2180                  tm->tm_year + 1900,
2181                  tm->tm_hour,
2182                  tm->tm_min,
2183                  tm->tm_sec);
2184         result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2185         if(result)
2186           return result;
2187       } /* end of a ridiculous amount of conditionals */
2188 #endif
2189     }
2190     break;
2191   default:
2192     infof(data, "unsupported MDTM reply format\n");
2193     break;
2194   case 550: /* "No such file or directory" */
2195     failf(data, "Given file does not exist");
2196     result = CURLE_FTP_COULDNT_RETR_FILE;
2197     break;
2198   }
2199
2200   if(data->set.timecondition) {
2201     if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
2202       switch(data->set.timecondition) {
2203       case CURL_TIMECOND_IFMODSINCE:
2204       default:
2205         if(data->info.filetime <= data->set.timevalue) {
2206           infof(data, "The requested document is not new enough\n");
2207           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2208           data->info.timecond = TRUE;
2209           state(conn, FTP_STOP);
2210           return CURLE_OK;
2211         }
2212         break;
2213       case CURL_TIMECOND_IFUNMODSINCE:
2214         if(data->info.filetime > data->set.timevalue) {
2215           infof(data, "The requested document is not old enough\n");
2216           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
2217           data->info.timecond = TRUE;
2218           state(conn, FTP_STOP);
2219           return CURLE_OK;
2220         }
2221         break;
2222       } /* switch */
2223     }
2224     else {
2225       infof(data, "Skipping time comparison\n");
2226     }
2227   }
2228
2229   if(!result)
2230     result = ftp_state_type(conn);
2231
2232   return result;
2233 }
2234
2235 static CURLcode ftp_state_type_resp(struct connectdata *conn,
2236                                     int ftpcode,
2237                                     ftpstate instate)
2238 {
2239   CURLcode result = CURLE_OK;
2240   struct SessionHandle *data=conn->data;
2241
2242   if(ftpcode/100 != 2) {
2243     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
2244        successful 'TYPE I'. While that is not as RFC959 says, it is still a
2245        positive response code and we allow that. */
2246     failf(data, "Couldn't set desired mode");
2247     return CURLE_FTP_COULDNT_SET_TYPE;
2248   }
2249   if(ftpcode != 200)
2250     infof(data, "Got a %03d response code instead of the assumed 200\n",
2251           ftpcode);
2252
2253   if(instate == FTP_TYPE)
2254     result = ftp_state_size(conn);
2255   else if(instate == FTP_LIST_TYPE)
2256     result = ftp_state_list(conn);
2257   else if(instate == FTP_RETR_TYPE)
2258     result = ftp_state_retr_prequote(conn);
2259   else if(instate == FTP_STOR_TYPE)
2260     result = ftp_state_stor_prequote(conn);
2261
2262   return result;
2263 }
2264
2265 static CURLcode ftp_state_retr(struct connectdata *conn,
2266                                          curl_off_t filesize)
2267 {
2268   CURLcode result = CURLE_OK;
2269   struct SessionHandle *data=conn->data;
2270   struct FTP *ftp = data->req.protop;
2271   struct ftp_conn *ftpc = &conn->proto.ftpc;
2272
2273   if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
2274     failf(data, "Maximum file size exceeded");
2275     return CURLE_FILESIZE_EXCEEDED;
2276   }
2277   ftp->downloadsize = filesize;
2278
2279   if(data->state.resume_from) {
2280     /* We always (attempt to) get the size of downloads, so it is done before
2281        this even when not doing resumes. */
2282     if(filesize == -1) {
2283       infof(data, "ftp server doesn't support SIZE\n");
2284       /* We couldn't get the size and therefore we can't know if there really
2285          is a part of the file left to get, although the server will just
2286          close the connection when we start the connection so it won't cause
2287          us any harm, just not make us exit as nicely. */
2288     }
2289     else {
2290       /* We got a file size report, so we check that there actually is a
2291          part of the file left to get, or else we go home.  */
2292       if(data->state.resume_from< 0) {
2293         /* We're supposed to download the last abs(from) bytes */
2294         if(filesize < -data->state.resume_from) {
2295           failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2296                 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2297                 data->state.resume_from, filesize);
2298           return CURLE_BAD_DOWNLOAD_RESUME;
2299         }
2300         /* convert to size to download */
2301         ftp->downloadsize = -data->state.resume_from;
2302         /* download from where? */
2303         data->state.resume_from = filesize - ftp->downloadsize;
2304       }
2305       else {
2306         if(filesize < data->state.resume_from) {
2307           failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
2308                 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
2309                 data->state.resume_from, filesize);
2310           return CURLE_BAD_DOWNLOAD_RESUME;
2311         }
2312         /* Now store the number of bytes we are expected to download */
2313         ftp->downloadsize = filesize-data->state.resume_from;
2314       }
2315     }
2316
2317     if(ftp->downloadsize == 0) {
2318       /* no data to transfer */
2319       Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
2320       infof(data, "File already completely downloaded\n");
2321
2322       /* Set ->transfer so that we won't get any error in ftp_done()
2323        * because we didn't transfer the any file */
2324       ftp->transfer = FTPTRANSFER_NONE;
2325       state(conn, FTP_STOP);
2326       return CURLE_OK;
2327     }
2328
2329     /* Set resume file transfer offset */
2330     infof(data, "Instructs server to resume from offset %"
2331           CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
2332
2333     PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
2334             data->state.resume_from);
2335
2336     state(conn, FTP_RETR_REST);
2337   }
2338   else {
2339     /* no resume */
2340     PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2341     state(conn, FTP_RETR);
2342   }
2343
2344   return result;
2345 }
2346
2347 static CURLcode ftp_state_size_resp(struct connectdata *conn,
2348                                     int ftpcode,
2349                                     ftpstate instate)
2350 {
2351   CURLcode result = CURLE_OK;
2352   struct SessionHandle *data=conn->data;
2353   curl_off_t filesize;
2354   char *buf = data->state.buffer;
2355
2356   /* get the size from the ascii string: */
2357   filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
2358
2359   if(instate == FTP_SIZE) {
2360 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2361     if(-1 != filesize) {
2362       snprintf(buf, sizeof(data->state.buffer),
2363                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
2364       result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2365       if(result)
2366         return result;
2367     }
2368 #endif
2369     Curl_pgrsSetDownloadSize(data, filesize);
2370     result = ftp_state_rest(conn);
2371   }
2372   else if(instate == FTP_RETR_SIZE) {
2373     Curl_pgrsSetDownloadSize(data, filesize);
2374     result = ftp_state_retr(conn, filesize);
2375   }
2376   else if(instate == FTP_STOR_SIZE) {
2377     data->state.resume_from = filesize;
2378     result = ftp_state_ul_setup(conn, TRUE);
2379   }
2380
2381   return result;
2382 }
2383
2384 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
2385                                     int ftpcode,
2386                                     ftpstate instate)
2387 {
2388   CURLcode result = CURLE_OK;
2389   struct ftp_conn *ftpc = &conn->proto.ftpc;
2390
2391   switch(instate) {
2392   case FTP_REST:
2393   default:
2394 #ifdef CURL_FTP_HTTPSTYLE_HEAD
2395     if(ftpcode == 350) {
2396       char buffer[24]= { "Accept-ranges: bytes\r\n" };
2397       result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
2398       if(result)
2399         return result;
2400     }
2401 #endif
2402     result = ftp_state_prepare_transfer(conn);
2403     break;
2404
2405   case FTP_RETR_REST:
2406     if(ftpcode != 350) {
2407       failf(conn->data, "Couldn't use REST");
2408       result = CURLE_FTP_COULDNT_USE_REST;
2409     }
2410     else {
2411       PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
2412       state(conn, FTP_RETR);
2413     }
2414     break;
2415   }
2416
2417   return result;
2418 }
2419
2420 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
2421                                     int ftpcode, ftpstate instate)
2422 {
2423   CURLcode result = CURLE_OK;
2424   struct SessionHandle *data = conn->data;
2425
2426   if(ftpcode>=400) {
2427     failf(data, "Failed FTP upload: %0d", ftpcode);
2428     state(conn, FTP_STOP);
2429     /* oops, we never close the sockets! */
2430     return CURLE_UPLOAD_FAILED;
2431   }
2432
2433   conn->proto.ftpc.state_saved = instate;
2434
2435   /* PORT means we are now awaiting the server to connect to us. */
2436   if(data->set.ftp_use_port) {
2437     bool connected;
2438
2439     state(conn, FTP_STOP); /* no longer in STOR state */
2440
2441     result = AllowServerConnect(conn, &connected);
2442     if(result)
2443       return result;
2444
2445     if(!connected) {
2446       struct ftp_conn *ftpc = &conn->proto.ftpc;
2447       infof(data, "Data conn was not available immediately\n");
2448       ftpc->wait_data_conn = TRUE;
2449     }
2450
2451     return CURLE_OK;
2452   }
2453   else
2454     return InitiateTransfer(conn);
2455 }
2456
2457 /* for LIST and RETR responses */
2458 static CURLcode ftp_state_get_resp(struct connectdata *conn,
2459                                     int ftpcode,
2460                                     ftpstate instate)
2461 {
2462   CURLcode result = CURLE_OK;
2463   struct SessionHandle *data = conn->data;
2464   struct FTP *ftp = data->req.protop;
2465   char *buf = data->state.buffer;
2466
2467   if((ftpcode == 150) || (ftpcode == 125)) {
2468
2469     /*
2470       A;
2471       150 Opening BINARY mode data connection for /etc/passwd (2241
2472       bytes).  (ok, the file is being transferred)
2473
2474       B:
2475       150 Opening ASCII mode data connection for /bin/ls
2476
2477       C:
2478       150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
2479
2480       D:
2481       150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
2482
2483       E:
2484       125 Data connection already open; Transfer starting. */
2485
2486     curl_off_t size=-1; /* default unknown size */
2487
2488
2489     /*
2490      * It appears that there are FTP-servers that return size 0 for files when
2491      * SIZE is used on the file while being in BINARY mode. To work around
2492      * that (stupid) behavior, we attempt to parse the RETR response even if
2493      * the SIZE returned size zero.
2494      *
2495      * Debugging help from Salvatore Sorrentino on February 26, 2003.
2496      */
2497
2498     if((instate != FTP_LIST) &&
2499        !data->set.prefer_ascii &&
2500        (ftp->downloadsize < 1)) {
2501       /*
2502        * It seems directory listings either don't show the size or very
2503        * often uses size 0 anyway. ASCII transfers may very well turn out
2504        * that the transferred amount of data is not the same as this line
2505        * tells, why using this number in those cases only confuses us.
2506        *
2507        * Example D above makes this parsing a little tricky */
2508       char *bytes;
2509       bytes=strstr(buf, " bytes");
2510       if(bytes--) {
2511         long in=(long)(bytes-buf);
2512         /* this is a hint there is size information in there! ;-) */
2513         while(--in) {
2514           /* scan for the left parenthesis and break there */
2515           if('(' == *bytes)
2516             break;
2517           /* skip only digits */
2518           if(!ISDIGIT(*bytes)) {
2519             bytes=NULL;
2520             break;
2521           }
2522           /* one more estep backwards */
2523           bytes--;
2524         }
2525         /* if we have nothing but digits: */
2526         if(bytes++) {
2527           /* get the number! */
2528           size = curlx_strtoofft(bytes, NULL, 0);
2529         }
2530       }
2531     }
2532     else if(ftp->downloadsize > -1)
2533       size = ftp->downloadsize;
2534
2535     if(size > data->req.maxdownload && data->req.maxdownload > 0)
2536       size = data->req.size = data->req.maxdownload;
2537     else if((instate != FTP_LIST) && (data->set.prefer_ascii))
2538       size = -1; /* kludge for servers that understate ASCII mode file size */
2539
2540     infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
2541           data->req.maxdownload);
2542
2543     if(instate != FTP_LIST)
2544       infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
2545             size);
2546
2547     /* FTP download: */
2548     conn->proto.ftpc.state_saved = instate;
2549     conn->proto.ftpc.retr_size_saved = size;
2550
2551     if(data->set.ftp_use_port) {
2552       bool connected;
2553
2554       result = AllowServerConnect(conn, &connected);
2555       if(result)
2556         return result;
2557
2558       if(!connected) {
2559         struct ftp_conn *ftpc = &conn->proto.ftpc;
2560         infof(data, "Data conn was not available immediately\n");
2561         state(conn, FTP_STOP);
2562         ftpc->wait_data_conn = TRUE;
2563       }
2564     }
2565     else
2566       return InitiateTransfer(conn);
2567   }
2568   else {
2569     if((instate == FTP_LIST) && (ftpcode == 450)) {
2570       /* simply no matching files in the dir listing */
2571       ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
2572       state(conn, FTP_STOP); /* this phase is over */
2573     }
2574     else {
2575       failf(data, "RETR response: %03d", ftpcode);
2576       return instate == FTP_RETR && ftpcode == 550?
2577         CURLE_REMOTE_FILE_NOT_FOUND:
2578         CURLE_FTP_COULDNT_RETR_FILE;
2579     }
2580   }
2581
2582   return result;
2583 }
2584
2585 /* after USER, PASS and ACCT */
2586 static CURLcode ftp_state_loggedin(struct connectdata *conn)
2587 {
2588   CURLcode result = CURLE_OK;
2589
2590   if(conn->ssl[FIRSTSOCKET].use) {
2591     /* PBSZ = PROTECTION BUFFER SIZE.
2592
2593     The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
2594
2595     Specifically, the PROT command MUST be preceded by a PBSZ
2596     command and a PBSZ command MUST be preceded by a successful
2597     security data exchange (the TLS negotiation in this case)
2598
2599     ... (and on page 8):
2600
2601     Thus the PBSZ command must still be issued, but must have a
2602     parameter of '0' to indicate that no buffering is taking place
2603     and the data connection should not be encapsulated.
2604     */
2605     PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
2606     state(conn, FTP_PBSZ);
2607   }
2608   else {
2609     result = ftp_state_pwd(conn);
2610   }
2611   return result;
2612 }
2613
2614 /* for USER and PASS responses */
2615 static CURLcode ftp_state_user_resp(struct connectdata *conn,
2616                                     int ftpcode,
2617                                     ftpstate instate)
2618 {
2619   CURLcode result = CURLE_OK;
2620   struct SessionHandle *data = conn->data;
2621   struct FTP *ftp = data->req.protop;
2622   struct ftp_conn *ftpc = &conn->proto.ftpc;
2623   (void)instate; /* no use for this yet */
2624
2625   /* some need password anyway, and others just return 2xx ignored */
2626   if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2627     /* 331 Password required for ...
2628        (the server requires to send the user's password too) */
2629     PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
2630     state(conn, FTP_PASS);
2631   }
2632   else if(ftpcode/100 == 2) {
2633     /* 230 User ... logged in.
2634        (the user logged in with or without password) */
2635     result = ftp_state_loggedin(conn);
2636   }
2637   else if(ftpcode == 332) {
2638     if(data->set.str[STRING_FTP_ACCOUNT]) {
2639       PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
2640       state(conn, FTP_ACCT);
2641     }
2642     else {
2643       failf(data, "ACCT requested but none available");
2644       result = CURLE_LOGIN_DENIED;
2645     }
2646   }
2647   else {
2648     /* All other response codes, like:
2649
2650     530 User ... access denied
2651     (the server denies to log the specified user) */
2652
2653     if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
2654         !conn->data->state.ftp_trying_alternative) {
2655       /* Ok, USER failed.  Let's try the supplied command. */
2656       PPSENDF(&conn->proto.ftpc.pp, "%s",
2657               conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
2658       conn->data->state.ftp_trying_alternative = TRUE;
2659       state(conn, FTP_USER);
2660       result = CURLE_OK;
2661     }
2662     else {
2663       failf(data, "Access denied: %03d", ftpcode);
2664       result = CURLE_LOGIN_DENIED;
2665     }
2666   }
2667   return result;
2668 }
2669
2670 /* for ACCT response */
2671 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
2672                                     int ftpcode)
2673 {
2674   CURLcode result = CURLE_OK;
2675   struct SessionHandle *data = conn->data;
2676   if(ftpcode != 230) {
2677     failf(data, "ACCT rejected by server: %03d", ftpcode);
2678     result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
2679   }
2680   else
2681     result = ftp_state_loggedin(conn);
2682
2683   return result;
2684 }
2685
2686
2687 static CURLcode ftp_statemach_act(struct connectdata *conn)
2688 {
2689   CURLcode result;
2690   curl_socket_t sock = conn->sock[FIRSTSOCKET];
2691   struct SessionHandle *data=conn->data;
2692   int ftpcode;
2693   struct ftp_conn *ftpc = &conn->proto.ftpc;
2694   struct pingpong *pp = &ftpc->pp;
2695   static const char ftpauth[][4]  = { "SSL", "TLS" };
2696   size_t nread = 0;
2697
2698   if(pp->sendleft)
2699     return Curl_pp_flushsend(pp);
2700
2701   result = ftp_readresp(sock, pp, &ftpcode, &nread);
2702   if(result)
2703     return result;
2704
2705   if(ftpcode) {
2706     /* we have now received a full FTP server response */
2707     switch(ftpc->state) {
2708     case FTP_WAIT220:
2709       if(ftpcode == 230)
2710         /* 230 User logged in - already! */
2711         return ftp_state_user_resp(conn, ftpcode, ftpc->state);
2712       else if(ftpcode != 220) {
2713         failf(data, "Got a %03d ftp-server response when 220 was expected",
2714               ftpcode);
2715         return CURLE_FTP_WEIRD_SERVER_REPLY;
2716       }
2717
2718       /* We have received a 220 response fine, now we proceed. */
2719 #ifdef HAVE_GSSAPI
2720       if(data->set.krb) {
2721         /* If not anonymous login, try a secure login. Note that this
2722            procedure is still BLOCKING. */
2723
2724         Curl_sec_request_prot(conn, "private");
2725         /* We set private first as default, in case the line below fails to
2726            set a valid level */
2727         Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2728
2729         if(Curl_sec_login(conn))
2730           infof(data, "Logging in with password in cleartext!\n");
2731         else
2732           infof(data, "Authentication successful\n");
2733       }
2734 #endif
2735
2736       if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
2737         /* We don't have a SSL/TLS connection yet, but FTPS is
2738            requested. Try a FTPS connection now */
2739
2740         ftpc->count3=0;
2741         switch(data->set.ftpsslauth) {
2742         case CURLFTPAUTH_DEFAULT:
2743         case CURLFTPAUTH_SSL:
2744           ftpc->count2 = 1; /* add one to get next */
2745           ftpc->count1 = 0;
2746           break;
2747         case CURLFTPAUTH_TLS:
2748           ftpc->count2 = -1; /* subtract one to get next */
2749           ftpc->count1 = 1;
2750           break;
2751         default:
2752           failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2753                 (int)data->set.ftpsslauth);
2754           return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2755         }
2756         PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2757         state(conn, FTP_AUTH);
2758       }
2759       else {
2760         result = ftp_state_user(conn);
2761         if(result)
2762           return result;
2763       }
2764
2765       break;
2766
2767     case FTP_AUTH:
2768       /* we have gotten the response to a previous AUTH command */
2769
2770       /* RFC2228 (page 5) says:
2771        *
2772        * If the server is willing to accept the named security mechanism,
2773        * and does not require any security data, it must respond with
2774        * reply code 234/334.
2775        */
2776
2777       if((ftpcode == 234) || (ftpcode == 334)) {
2778         /* Curl_ssl_connect is BLOCKING */
2779         result = Curl_ssl_connect(conn, FIRSTSOCKET);
2780         if(!result) {
2781           conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2782           result = ftp_state_user(conn);
2783         }
2784       }
2785       else if(ftpc->count3 < 1) {
2786         ftpc->count3++;
2787         ftpc->count1 += ftpc->count2; /* get next attempt */
2788         result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2789         /* remain in this same state */
2790       }
2791       else {
2792         if(data->set.use_ssl > CURLUSESSL_TRY)
2793           /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2794           result = CURLE_USE_SSL_FAILED;
2795         else
2796           /* ignore the failure and continue */
2797           result = ftp_state_user(conn);
2798       }
2799
2800       if(result)
2801         return result;
2802       break;
2803
2804     case FTP_USER:
2805     case FTP_PASS:
2806       result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2807       break;
2808
2809     case FTP_ACCT:
2810       result = ftp_state_acct_resp(conn, ftpcode);
2811       break;
2812
2813     case FTP_PBSZ:
2814       PPSENDF(&ftpc->pp, "PROT %c",
2815               data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2816       state(conn, FTP_PROT);
2817
2818       break;
2819
2820     case FTP_PROT:
2821       if(ftpcode/100 == 2)
2822         /* We have enabled SSL for the data connection! */
2823         conn->ssl[SECONDARYSOCKET].use =
2824           (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2825       /* FTP servers typically responds with 500 if they decide to reject
2826          our 'P' request */
2827       else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2828         /* we failed and bails out */
2829         return CURLE_USE_SSL_FAILED;
2830
2831       if(data->set.ftp_ccc) {
2832         /* CCC - Clear Command Channel
2833          */
2834         PPSENDF(&ftpc->pp, "%s", "CCC");
2835         state(conn, FTP_CCC);
2836       }
2837       else {
2838         result = ftp_state_pwd(conn);
2839         if(result)
2840           return result;
2841       }
2842       break;
2843
2844     case FTP_CCC:
2845       if(ftpcode < 500) {
2846         /* First shut down the SSL layer (note: this call will block) */
2847         result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2848
2849         if(result) {
2850           failf(conn->data, "Failed to clear the command channel (CCC)");
2851           return result;
2852         }
2853       }
2854
2855       /* Then continue as normal */
2856       result = ftp_state_pwd(conn);
2857       if(result)
2858         return result;
2859       break;
2860
2861     case FTP_PWD:
2862       if(ftpcode == 257) {
2863         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2864         char *dir;
2865         char *store;
2866
2867         dir = malloc(nread + 1);
2868         if(!dir)
2869           return CURLE_OUT_OF_MEMORY;
2870
2871         /* Reply format is like
2872            257<space>[rubbish]"<directory-name>"<space><commentary> and the
2873            RFC959 says
2874
2875            The directory name can contain any character; embedded
2876            double-quotes should be escaped by double-quotes (the
2877            "quote-doubling" convention).
2878         */
2879
2880         /* scan for the first double-quote for non-standard responses */
2881         while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
2882               && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
2883           ptr++;
2884
2885         if('\"' == *ptr) {
2886           /* it started good */
2887           ptr++;
2888           for(store = dir; *ptr;) {
2889             if('\"' == *ptr) {
2890               if('\"' == ptr[1]) {
2891                 /* "quote-doubling" */
2892                 *store = ptr[1];
2893                 ptr++;
2894               }
2895               else {
2896                 /* end of path */
2897                 *store = '\0'; /* zero terminate */
2898                 break; /* get out of this loop */
2899               }
2900             }
2901             else
2902               *store = *ptr;
2903             store++;
2904             ptr++;
2905           }
2906
2907           /* If the path name does not look like an absolute path (i.e.: it
2908              does not start with a '/'), we probably need some server-dependent
2909              adjustments. For example, this is the case when connecting to
2910              an OS400 FTP server: this server supports two name syntaxes,
2911              the default one being incompatible with standard pathes. In
2912              addition, this server switches automatically to the regular path
2913              syntax when one is encountered in a command: this results in
2914              having an entrypath in the wrong syntax when later used in CWD.
2915                The method used here is to check the server OS: we do it only
2916              if the path name looks strange to minimize overhead on other
2917              systems. */
2918
2919           if(!ftpc->server_os && dir[0] != '/') {
2920
2921             result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
2922             if(result) {
2923               free(dir);
2924               return result;
2925             }
2926             Curl_safefree(ftpc->entrypath);
2927             ftpc->entrypath = dir; /* remember this */
2928             infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2929             /* also save it where getinfo can access it: */
2930             data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2931             state(conn, FTP_SYST);
2932             break;
2933           }
2934
2935           Curl_safefree(ftpc->entrypath);
2936           ftpc->entrypath = dir; /* remember this */
2937           infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2938           /* also save it where getinfo can access it: */
2939           data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2940         }
2941         else {
2942           /* couldn't get the path */
2943           free(dir);
2944           infof(data, "Failed to figure out path\n");
2945         }
2946       }
2947       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2948       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2949       break;
2950
2951     case FTP_SYST:
2952       if(ftpcode == 215) {
2953         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2954         char *os;
2955         char *store;
2956
2957         os = malloc(nread + 1);
2958         if(!os)
2959           return CURLE_OUT_OF_MEMORY;
2960
2961         /* Reply format is like
2962            215<space><OS-name><space><commentary>
2963         */
2964         while(*ptr == ' ')
2965           ptr++;
2966         for(store = os; *ptr && *ptr != ' ';)
2967           *store++ = *ptr++;
2968         *store = '\0'; /* zero terminate */
2969
2970         /* Check for special servers here. */
2971
2972         if(strequal(os, "OS/400")) {
2973           /* Force OS400 name format 1. */
2974           result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
2975           if(result) {
2976             free(os);
2977             return result;
2978           }
2979           /* remember target server OS */
2980           Curl_safefree(ftpc->server_os);
2981           ftpc->server_os = os;
2982           state(conn, FTP_NAMEFMT);
2983           break;
2984         }
2985         else {
2986           /* Nothing special for the target server. */
2987           /* remember target server OS */
2988           Curl_safefree(ftpc->server_os);
2989           ftpc->server_os = os;
2990         }
2991       }
2992       else {
2993         /* Cannot identify server OS. Continue anyway and cross fingers. */
2994       }
2995
2996       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2997       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2998       break;
2999
3000     case FTP_NAMEFMT:
3001       if(ftpcode == 250) {
3002         /* Name format change successful: reload initial path. */
3003         ftp_state_pwd(conn);
3004         break;
3005       }
3006
3007       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
3008       DEBUGF(infof(data, "protocol connect phase DONE\n"));
3009       break;
3010
3011     case FTP_QUOTE:
3012     case FTP_POSTQUOTE:
3013     case FTP_RETR_PREQUOTE:
3014     case FTP_STOR_PREQUOTE:
3015       if((ftpcode >= 400) && !ftpc->count2) {
3016         /* failure response code, and not allowed to fail */
3017         failf(conn->data, "QUOT command failed with %03d", ftpcode);
3018         return CURLE_QUOTE_ERROR;
3019       }
3020       result = ftp_state_quote(conn, FALSE, ftpc->state);
3021       if(result)
3022         return result;
3023
3024       break;
3025
3026     case FTP_CWD:
3027       if(ftpcode/100 != 2) {
3028         /* failure to CWD there */
3029         if(conn->data->set.ftp_create_missing_dirs &&
3030            ftpc->count1 && !ftpc->count2) {
3031           /* try making it */
3032           ftpc->count2++; /* counter to prevent CWD-MKD loops */
3033           PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
3034           state(conn, FTP_MKD);
3035         }
3036         else {
3037           /* return failure */
3038           failf(data, "Server denied you to change to the given directory");
3039           ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3040                                    to enter it */
3041           return CURLE_REMOTE_ACCESS_DENIED;
3042         }
3043       }
3044       else {
3045         /* success */
3046         ftpc->count2=0;
3047         if(++ftpc->count1 <= ftpc->dirdepth) {
3048           /* send next CWD */
3049           PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3050         }
3051         else {
3052           result = ftp_state_mdtm(conn);
3053           if(result)
3054             return result;
3055         }
3056       }
3057       break;
3058
3059     case FTP_MKD:
3060       if((ftpcode/100 != 2) && !ftpc->count3--) {
3061         /* failure to MKD the dir */
3062         failf(data, "Failed to MKD dir: %03d", ftpcode);
3063         return CURLE_REMOTE_ACCESS_DENIED;
3064       }
3065       state(conn, FTP_CWD);
3066       /* send CWD */
3067       PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3068       break;
3069
3070     case FTP_MDTM:
3071       result = ftp_state_mdtm_resp(conn, ftpcode);
3072       break;
3073
3074     case FTP_TYPE:
3075     case FTP_LIST_TYPE:
3076     case FTP_RETR_TYPE:
3077     case FTP_STOR_TYPE:
3078       result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3079       break;
3080
3081     case FTP_SIZE:
3082     case FTP_RETR_SIZE:
3083     case FTP_STOR_SIZE:
3084       result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3085       break;
3086
3087     case FTP_REST:
3088     case FTP_RETR_REST:
3089       result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3090       break;
3091
3092     case FTP_PRET:
3093       if(ftpcode != 200) {
3094         /* there only is this one standard OK return code. */
3095         failf(data, "PRET command not accepted: %03d", ftpcode);
3096         return CURLE_FTP_PRET_FAILED;
3097       }
3098       result = ftp_state_use_pasv(conn);
3099       break;
3100
3101     case FTP_PASV:
3102       result = ftp_state_pasv_resp(conn, ftpcode);
3103       break;
3104
3105     case FTP_PORT:
3106       result = ftp_state_port_resp(conn, ftpcode);
3107       break;
3108
3109     case FTP_LIST:
3110     case FTP_RETR:
3111       result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3112       break;
3113
3114     case FTP_STOR:
3115       result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3116       break;
3117
3118     case FTP_QUIT:
3119       /* fallthrough, just stop! */
3120     default:
3121       /* internal error */
3122       state(conn, FTP_STOP);
3123       break;
3124     }
3125   } /* if(ftpcode) */
3126
3127   return result;
3128 }
3129
3130
3131 /* called repeatedly until done from multi.c */
3132 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3133                                     bool *done)
3134 {
3135   struct ftp_conn *ftpc = &conn->proto.ftpc;
3136   CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
3137
3138   /* Check for the state outside of the Curl_socket_ready() return code checks
3139      since at times we are in fact already in this state when this function
3140      gets called. */
3141   *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3142
3143   return result;
3144 }
3145
3146 static CURLcode ftp_block_statemach(struct connectdata *conn)
3147 {
3148   struct ftp_conn *ftpc = &conn->proto.ftpc;
3149   struct pingpong *pp = &ftpc->pp;
3150   CURLcode result = CURLE_OK;
3151
3152   while(ftpc->state != FTP_STOP) {
3153     result = Curl_pp_statemach(pp, TRUE);
3154     if(result)
3155       break;
3156   }
3157
3158   return result;
3159 }
3160
3161 /*
3162  * ftp_connect() should do everything that is to be considered a part of
3163  * the connection phase.
3164  *
3165  * The variable 'done' points to will be TRUE if the protocol-layer connect
3166  * phase is done when this function returns, or FALSE if not.
3167  *
3168  */
3169 static CURLcode ftp_connect(struct connectdata *conn,
3170                                  bool *done) /* see description above */
3171 {
3172   CURLcode result;
3173   struct ftp_conn *ftpc = &conn->proto.ftpc;
3174   struct pingpong *pp = &ftpc->pp;
3175
3176   *done = FALSE; /* default to not done yet */
3177
3178   /* We always support persistent connections on ftp */
3179   connkeep(conn, "FTP default");
3180
3181   pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3182   pp->statemach_act = ftp_statemach_act;
3183   pp->endofresp = ftp_endofresp;
3184   pp->conn = conn;
3185
3186   if(conn->handler->flags & PROTOPT_SSL) {
3187     /* BLOCKING */
3188     result = Curl_ssl_connect(conn, FIRSTSOCKET);
3189     if(result)
3190       return result;
3191   }
3192
3193   Curl_pp_init(pp); /* init the generic pingpong data */
3194
3195   /* When we connect, we start in the state where we await the 220
3196      response */
3197   state(conn, FTP_WAIT220);
3198
3199   result = ftp_multi_statemach(conn, done);
3200
3201   return result;
3202 }
3203
3204 /***********************************************************************
3205  *
3206  * ftp_done()
3207  *
3208  * The DONE function. This does what needs to be done after a single DO has
3209  * performed.
3210  *
3211  * Input argument is already checked for validity.
3212  */
3213 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3214                               bool premature)
3215 {
3216   struct SessionHandle *data = conn->data;
3217   struct FTP *ftp = data->req.protop;
3218   struct ftp_conn *ftpc = &conn->proto.ftpc;
3219   struct pingpong *pp = &ftpc->pp;
3220   ssize_t nread;
3221   int ftpcode;
3222   CURLcode result = CURLE_OK;
3223   bool was_ctl_valid = ftpc->ctl_valid;
3224   char *path;
3225   const char *path_to_use = data->state.path;
3226
3227   if(!ftp)
3228     /* When the easy handle is removed from the multi while libcurl is still
3229      * trying to resolve the host name, it seems that the ftp struct is not
3230      * yet initialized, but the removal action calls Curl_done() which calls
3231      * this function. So we simply return success if no ftp pointer is set.
3232      */
3233     return CURLE_OK;
3234
3235   switch(status) {
3236   case CURLE_BAD_DOWNLOAD_RESUME:
3237   case CURLE_FTP_WEIRD_PASV_REPLY:
3238   case CURLE_FTP_PORT_FAILED:
3239   case CURLE_FTP_ACCEPT_FAILED:
3240   case CURLE_FTP_ACCEPT_TIMEOUT:
3241   case CURLE_FTP_COULDNT_SET_TYPE:
3242   case CURLE_FTP_COULDNT_RETR_FILE:
3243   case CURLE_PARTIAL_FILE:
3244   case CURLE_UPLOAD_FAILED:
3245   case CURLE_REMOTE_ACCESS_DENIED:
3246   case CURLE_FILESIZE_EXCEEDED:
3247   case CURLE_REMOTE_FILE_NOT_FOUND:
3248   case CURLE_WRITE_ERROR:
3249     /* the connection stays alive fine even though this happened */
3250     /* fall-through */
3251   case CURLE_OK: /* doesn't affect the control connection's status */
3252     if(!premature) {
3253       ftpc->ctl_valid = was_ctl_valid;
3254       break;
3255     }
3256     /* until we cope better with prematurely ended requests, let them
3257      * fallback as if in complete failure */
3258   default:       /* by default, an error means the control connection is
3259                     wedged and should not be used anymore */
3260     ftpc->ctl_valid = FALSE;
3261     ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3262                              current path, as this connection is going */
3263     connclose(conn, "FTP ended with bad error code");
3264     result = status;      /* use the already set error code */
3265     break;
3266   }
3267
3268   /* now store a copy of the directory we are in */
3269   if(ftpc->prevpath)
3270     free(ftpc->prevpath);
3271
3272   if(data->set.wildcardmatch) {
3273     if(data->set.chunk_end && ftpc->file) {
3274       data->set.chunk_end(data->wildcard.customptr);
3275     }
3276     ftpc->known_filesize = -1;
3277   }
3278
3279   /* get the "raw" path */
3280   path = curl_easy_unescape(data, path_to_use, 0, NULL);
3281   if(!path) {
3282     /* out of memory, but we can limp along anyway (and should try to
3283      * since we may already be in the out of memory cleanup path) */
3284     if(!result)
3285       result = CURLE_OUT_OF_MEMORY;
3286     ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3287     connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
3288     ftpc->prevpath = NULL; /* no path remembering */
3289   }
3290   else {
3291     size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3292     size_t dlen = strlen(path)-flen;
3293     if(!ftpc->cwdfail) {
3294       if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3295         ftpc->prevpath = path;
3296         if(flen)
3297           /* if 'path' is not the whole string */
3298           ftpc->prevpath[dlen]=0; /* terminate */
3299       }
3300       else {
3301         /* we never changed dir */
3302         ftpc->prevpath=strdup("");
3303         free(path);
3304       }
3305       if(ftpc->prevpath)
3306         infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3307     }
3308     else {
3309       ftpc->prevpath = NULL; /* no path */
3310       free(path);
3311     }
3312   }
3313   /* free the dir tree and file parts */
3314   freedirs(ftpc);
3315
3316   /* shut down the socket to inform the server we're done */
3317
3318 #ifdef _WIN32_WCE
3319   shutdown(conn->sock[SECONDARYSOCKET],2);  /* SD_BOTH */
3320 #endif
3321
3322   if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3323     if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
3324       /* partial download completed */
3325       result = Curl_pp_sendf(pp, "%s", "ABOR");
3326       if(result) {
3327         failf(data, "Failure sending ABOR command: %s",
3328               curl_easy_strerror(result));
3329         ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3330         connclose(conn, "ABOR command failed"); /* connection closure */
3331       }
3332     }
3333
3334     if(conn->ssl[SECONDARYSOCKET].use) {
3335       /* The secondary socket is using SSL so we must close down that part
3336          first before we close the socket for real */
3337       Curl_ssl_close(conn, SECONDARYSOCKET);
3338
3339       /* Note that we keep "use" set to TRUE since that (next) connection is
3340          still requested to use SSL */
3341     }
3342     if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3343       Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
3344       conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3345       conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
3346     }
3347   }
3348
3349   if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3350      pp->pending_resp && !premature) {
3351     /*
3352      * Let's see what the server says about the transfer we just performed,
3353      * but lower the timeout as sometimes this connection has died while the
3354      * data has been transferred. This happens when doing through NATs etc that
3355      * abandon old silent connections.
3356      */
3357     long old_time = pp->response_time;
3358
3359     pp->response_time = 60*1000; /* give it only a minute for now */
3360     pp->response = Curl_tvnow(); /* timeout relative now */
3361
3362     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3363
3364     pp->response_time = old_time; /* set this back to previous value */
3365
3366     if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3367       failf(data, "control connection looks dead");
3368       ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3369       connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
3370     }
3371
3372     if(result)
3373       return result;
3374
3375     if(ftpc->dont_check && data->req.maxdownload > 0) {
3376       /* we have just sent ABOR and there is no reliable way to check if it was
3377        * successful or not; we have to close the connection now */
3378       infof(data, "partial download completed, closing connection\n");
3379       connclose(conn, "Partial download with no ability to check");
3380       return result;
3381     }
3382
3383     if(!ftpc->dont_check) {
3384       /* 226 Transfer complete, 250 Requested file action okay, completed. */
3385       if((ftpcode != 226) && (ftpcode != 250)) {
3386         failf(data, "server did not report OK, got %d", ftpcode);
3387         result = CURLE_PARTIAL_FILE;
3388       }
3389     }
3390   }
3391
3392   if(result || premature)
3393     /* the response code from the transfer showed an error already so no
3394        use checking further */
3395     ;
3396   else if(data->set.upload) {
3397     if((-1 != data->state.infilesize) &&
3398        (data->state.infilesize != *ftp->bytecountp) &&
3399        !data->set.crlf &&
3400        (ftp->transfer == FTPTRANSFER_BODY)) {
3401       failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
3402             " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
3403             *ftp->bytecountp, data->state.infilesize);
3404       result = CURLE_PARTIAL_FILE;
3405     }
3406   }
3407   else {
3408     if((-1 != data->req.size) &&
3409        (data->req.size != *ftp->bytecountp) &&
3410 #ifdef CURL_DO_LINEEND_CONV
3411        /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3412         * we'll check to see if the discrepancy can be explained by the number
3413         * of CRLFs we've changed to LFs.
3414         */
3415        ((data->req.size + data->state.crlf_conversions) !=
3416         *ftp->bytecountp) &&
3417 #endif /* CURL_DO_LINEEND_CONV */
3418        (data->req.maxdownload != *ftp->bytecountp)) {
3419       failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
3420             " bytes", *ftp->bytecountp);
3421       result = CURLE_PARTIAL_FILE;
3422     }
3423     else if(!ftpc->dont_check &&
3424             !*ftp->bytecountp &&
3425             (data->req.size>0)) {
3426       failf(data, "No data was received!");
3427       result = CURLE_FTP_COULDNT_RETR_FILE;
3428     }
3429   }
3430
3431   /* clear these for next connection */
3432   ftp->transfer = FTPTRANSFER_BODY;
3433   ftpc->dont_check = FALSE;
3434
3435   /* Send any post-transfer QUOTE strings? */
3436   if(!status && !result && !premature && data->set.postquote)
3437     result = ftp_sendquote(conn, data->set.postquote);
3438
3439   return result;
3440 }
3441
3442 /***********************************************************************
3443  *
3444  * ftp_sendquote()
3445  *
3446  * Where a 'quote' means a list of custom commands to send to the server.
3447  * The quote list is passed as an argument.
3448  *
3449  * BLOCKING
3450  */
3451
3452 static
3453 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3454 {
3455   struct curl_slist *item;
3456   ssize_t nread;
3457   int ftpcode;
3458   CURLcode result;
3459   struct ftp_conn *ftpc = &conn->proto.ftpc;
3460   struct pingpong *pp = &ftpc->pp;
3461
3462   item = quote;
3463   while(item) {
3464     if(item->data) {
3465       char *cmd = item->data;
3466       bool acceptfail = FALSE;
3467
3468       /* if a command starts with an asterisk, which a legal FTP command never
3469          can, the command will be allowed to fail without it causing any
3470          aborts or cancels etc. It will cause libcurl to act as if the command
3471          is successful, whatever the server reponds. */
3472
3473       if(cmd[0] == '*') {
3474         cmd++;
3475         acceptfail = TRUE;
3476       }
3477
3478       PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
3479
3480       pp->response = Curl_tvnow(); /* timeout relative now */
3481
3482       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3483       if(result)
3484         return result;
3485
3486       if(!acceptfail && (ftpcode >= 400)) {
3487         failf(conn->data, "QUOT string not accepted: %s", cmd);
3488         return CURLE_QUOTE_ERROR;
3489       }
3490     }
3491
3492     item = item->next;
3493   }
3494
3495   return CURLE_OK;
3496 }
3497
3498 /***********************************************************************
3499  *
3500  * ftp_need_type()
3501  *
3502  * Returns TRUE if we in the current situation should send TYPE
3503  */
3504 static int ftp_need_type(struct connectdata *conn,
3505                          bool ascii_wanted)
3506 {
3507   return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3508 }
3509
3510 /***********************************************************************
3511  *
3512  * ftp_nb_type()
3513  *
3514  * Set TYPE. We only deal with ASCII or BINARY so this function
3515  * sets one of them.
3516  * If the transfer type is not sent, simulate on OK response in newstate
3517  */
3518 static CURLcode ftp_nb_type(struct connectdata *conn,
3519                             bool ascii, ftpstate newstate)
3520 {
3521   struct ftp_conn *ftpc = &conn->proto.ftpc;
3522   CURLcode result;
3523   char want = (char)(ascii?'A':'I');
3524
3525   if(ftpc->transfertype == want) {
3526     state(conn, newstate);
3527     return ftp_state_type_resp(conn, 200, newstate);
3528   }
3529
3530   PPSENDF(&ftpc->pp, "TYPE %c", want);
3531   state(conn, newstate);
3532
3533   /* keep track of our current transfer type */
3534   ftpc->transfertype = want;
3535   return CURLE_OK;
3536 }
3537
3538 /***************************************************************************
3539  *
3540  * ftp_pasv_verbose()
3541  *
3542  * This function only outputs some informationals about this second connection
3543  * when we've issued a PASV command before and thus we have connected to a
3544  * possibly new IP address.
3545  *
3546  */
3547 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3548 static void
3549 ftp_pasv_verbose(struct connectdata *conn,
3550                  Curl_addrinfo *ai,
3551                  char *newhost, /* ascii version */
3552                  int port)
3553 {
3554   char buf[256];
3555   Curl_printable_address(ai, buf, sizeof(buf));
3556   infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3557 }
3558 #endif
3559
3560 /*
3561   Check if this is a range download, and if so, set the internal variables
3562   properly.
3563  */
3564
3565 static CURLcode ftp_range(struct connectdata *conn)
3566 {
3567   curl_off_t from, to;
3568   char *ptr;
3569   char *ptr2;
3570   struct SessionHandle *data = conn->data;
3571   struct ftp_conn *ftpc = &conn->proto.ftpc;
3572
3573   if(data->state.use_range && data->state.range) {
3574     from=curlx_strtoofft(data->state.range, &ptr, 0);
3575     while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3576       ptr++;
3577     to=curlx_strtoofft(ptr, &ptr2, 0);
3578     if(ptr == ptr2) {
3579       /* we didn't get any digit */
3580       to=-1;
3581     }
3582     if((-1 == to) && (from>=0)) {
3583       /* X - */
3584       data->state.resume_from = from;
3585       DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
3586                    " to end of file\n", from));
3587     }
3588     else if(from < 0) {
3589       /* -Y */
3590       data->req.maxdownload = -from;
3591       data->state.resume_from = from;
3592       DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
3593                    " bytes\n", -from));
3594     }
3595     else {
3596       /* X-Y */
3597       data->req.maxdownload = (to-from)+1; /* include last byte */
3598       data->state.resume_from = from;
3599       DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
3600                    " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
3601                    from, data->req.maxdownload));
3602     }
3603     DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
3604                  " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
3605                  CURL_FORMAT_CURL_OFF_T " bytes\n",
3606                  from, to, data->req.maxdownload));
3607     ftpc->dont_check = TRUE; /* dont check for successful transfer */
3608   }
3609   else
3610     data->req.maxdownload = -1;
3611   return CURLE_OK;
3612 }
3613
3614
3615 /*
3616  * ftp_do_more()
3617  *
3618  * This function shall be called when the second FTP (data) connection is
3619  * connected.
3620  *
3621  * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3622  * (which basically is only for when PASV is being sent to retry a failed
3623  * EPSV).
3624  */
3625
3626 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
3627 {
3628   struct SessionHandle *data=conn->data;
3629   struct ftp_conn *ftpc = &conn->proto.ftpc;
3630   CURLcode result = CURLE_OK;
3631   bool connected = FALSE;
3632   bool complete = FALSE;
3633
3634   /* the ftp struct is inited in ftp_connect() */
3635   struct FTP *ftp = data->req.protop;
3636
3637   /* if the second connection isn't done yet, wait for it */
3638   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3639     if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
3640       /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3641          aren't used so we blank their arguments. TODO: make this nicer */
3642       result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
3643
3644       return result;
3645     }
3646
3647     result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3648
3649     /* Ready to do more? */
3650     if(connected) {
3651       DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3652       if(conn->bits.proxy) {
3653         infof(data, "Connection to proxy confirmed\n");
3654         result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected);
3655       }
3656     }
3657     else {
3658       if(result && (ftpc->count1 == 0)) {
3659         *completep = -1; /* go back to DOING please */
3660         /* this is a EPSV connect failing, try PASV instead */
3661         return ftp_epsv_disable(conn);
3662       }
3663       return result;
3664     }
3665   }
3666
3667   if(ftpc->state) {
3668     /* already in a state so skip the intial commands.
3669        They are only done to kickstart the do_more state */
3670     result = ftp_multi_statemach(conn, &complete);
3671
3672     *completep = (int)complete;
3673
3674     /* if we got an error or if we don't wait for a data connection return
3675        immediately */
3676     if(result || (ftpc->wait_data_conn != TRUE))
3677       return result;
3678
3679     if(ftpc->wait_data_conn)
3680       /* if we reach the end of the FTP state machine here, *complete will be
3681          TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3682          the data connection and therefore we're not actually complete */
3683       *completep = 0;
3684   }
3685
3686   if(ftp->transfer <= FTPTRANSFER_INFO) {
3687     /* a transfer is about to take place, or if not a file name was given
3688        so we'll do a SIZE on it later and then we need the right TYPE first */
3689
3690     if(ftpc->wait_data_conn == TRUE) {
3691       bool serv_conned;
3692
3693       result = ReceivedServerConnect(conn, &serv_conned);
3694       if(result)
3695         return result; /* Failed to accept data connection */
3696
3697       if(serv_conned) {
3698         /* It looks data connection is established */
3699         result = AcceptServerConnect(conn);
3700         ftpc->wait_data_conn = FALSE;
3701         if(!result)
3702           result = InitiateTransfer(conn);
3703
3704         if(result)
3705           return result;
3706
3707         *completep = 1; /* this state is now complete when the server has
3708                            connected back to us */
3709       }
3710     }
3711     else if(data->set.upload) {
3712       result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3713       if(result)
3714         return result;
3715
3716       result = ftp_multi_statemach(conn, &complete);
3717       *completep = (int)complete;
3718     }
3719     else {
3720       /* download */
3721       ftp->downloadsize = -1; /* unknown as of yet */
3722
3723       result = ftp_range(conn);
3724       if(result)
3725         ;
3726       else if(data->set.ftp_list_only || !ftpc->file) {
3727         /* The specified path ends with a slash, and therefore we think this
3728            is a directory that is requested, use LIST. But before that we
3729            need to set ASCII transfer mode. */
3730
3731         /* But only if a body transfer was requested. */
3732         if(ftp->transfer == FTPTRANSFER_BODY) {
3733           result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3734           if(result)
3735             return result;
3736         }
3737         /* otherwise just fall through */
3738       }
3739       else {
3740         result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3741         if(result)
3742           return result;
3743       }
3744
3745       result = ftp_multi_statemach(conn, &complete);
3746       *completep = (int)complete;
3747     }
3748     return result;
3749   }
3750
3751   if(!result && (ftp->transfer != FTPTRANSFER_BODY))
3752     /* no data to transfer. FIX: it feels like a kludge to have this here
3753        too! */
3754     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3755
3756   if(!ftpc->wait_data_conn) {
3757     /* no waiting for the data connection so this is now complete */
3758     *completep = 1;
3759     DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3760   }
3761
3762   return result;
3763 }
3764
3765
3766
3767 /***********************************************************************
3768  *
3769  * ftp_perform()
3770  *
3771  * This is the actual DO function for FTP. Get a file/directory according to
3772  * the options previously setup.
3773  */
3774
3775 static
3776 CURLcode ftp_perform(struct connectdata *conn,
3777                      bool *connected,  /* connect status after PASV / PORT */
3778                      bool *dophase_done)
3779 {
3780   /* this is FTP and no proxy */
3781   CURLcode result=CURLE_OK;
3782
3783   DEBUGF(infof(conn->data, "DO phase starts\n"));
3784
3785   if(conn->data->set.opt_no_body) {
3786     /* requested no body means no transfer... */
3787     struct FTP *ftp = conn->data->req.protop;
3788     ftp->transfer = FTPTRANSFER_INFO;
3789   }
3790
3791   *dophase_done = FALSE; /* not done yet */
3792
3793   /* start the first command in the DO phase */
3794   result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3795   if(result)
3796     return result;
3797
3798   /* run the state-machine */
3799   result = ftp_multi_statemach(conn, dophase_done);
3800
3801   *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
3802
3803   infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
3804
3805   if(*dophase_done)
3806     DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3807
3808   return result;
3809 }
3810
3811 static void wc_data_dtor(void *ptr)
3812 {
3813   struct ftp_wc_tmpdata *tmp = ptr;
3814   if(tmp)
3815     Curl_ftp_parselist_data_free(&tmp->parser);
3816   Curl_safefree(tmp);
3817 }
3818
3819 static CURLcode init_wc_data(struct connectdata *conn)
3820 {
3821   char *last_slash;
3822   char *path = conn->data->state.path;
3823   struct WildcardData *wildcard = &(conn->data->wildcard);
3824   CURLcode result = CURLE_OK;
3825   struct ftp_wc_tmpdata *ftp_tmp;
3826
3827   last_slash = strrchr(conn->data->state.path, '/');
3828   if(last_slash) {
3829     last_slash++;
3830     if(last_slash[0] == '\0') {
3831       wildcard->state = CURLWC_CLEAN;
3832       result = ftp_parse_url_path(conn);
3833       return result;
3834     }
3835     else {
3836       wildcard->pattern = strdup(last_slash);
3837       if(!wildcard->pattern)
3838         return CURLE_OUT_OF_MEMORY;
3839       last_slash[0] = '\0'; /* cut file from path */
3840     }
3841   }
3842   else { /* there is only 'wildcard pattern' or nothing */
3843     if(path[0]) {
3844       wildcard->pattern = strdup(path);
3845       if(!wildcard->pattern)
3846         return CURLE_OUT_OF_MEMORY;
3847       path[0] = '\0';
3848     }
3849     else { /* only list */
3850       wildcard->state = CURLWC_CLEAN;
3851       result = ftp_parse_url_path(conn);
3852       return result;
3853     }
3854   }
3855
3856   /* program continues only if URL is not ending with slash, allocate needed
3857      resources for wildcard transfer */
3858
3859   /* allocate ftp protocol specific temporary wildcard data */
3860   ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3861   if(!ftp_tmp) {
3862     Curl_safefree(wildcard->pattern);
3863     return CURLE_OUT_OF_MEMORY;
3864   }
3865
3866   /* INITIALIZE parselist structure */
3867   ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3868   if(!ftp_tmp->parser) {
3869     Curl_safefree(wildcard->pattern);
3870     Curl_safefree(ftp_tmp);
3871     return CURLE_OUT_OF_MEMORY;
3872   }
3873
3874   wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3875   wildcard->tmp_dtor = wc_data_dtor;
3876
3877   /* wildcard does not support NOCWD option (assert it?) */
3878   if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3879     conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3880
3881   /* try to parse ftp url */
3882   result = ftp_parse_url_path(conn);
3883   if(result) {
3884     Curl_safefree(wildcard->pattern);
3885     wildcard->tmp_dtor(wildcard->tmp);
3886     wildcard->tmp_dtor = ZERO_NULL;
3887     wildcard->tmp = NULL;
3888     return result;
3889   }
3890
3891   wildcard->path = strdup(conn->data->state.path);
3892   if(!wildcard->path) {
3893     Curl_safefree(wildcard->pattern);
3894     wildcard->tmp_dtor(wildcard->tmp);
3895     wildcard->tmp_dtor = ZERO_NULL;
3896     wildcard->tmp = NULL;
3897     return CURLE_OUT_OF_MEMORY;
3898   }
3899
3900   /* backup old write_function */
3901   ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3902   /* parsing write function */
3903   conn->data->set.fwrite_func = Curl_ftp_parselist;
3904   /* backup old file descriptor */
3905   ftp_tmp->backup.file_descriptor = conn->data->set.out;
3906   /* let the writefunc callback know what curl pointer is working with */
3907   conn->data->set.out = conn;
3908
3909   infof(conn->data, "Wildcard - Parsing started\n");
3910   return CURLE_OK;
3911 }
3912
3913 /* This is called recursively */
3914 static CURLcode wc_statemach(struct connectdata *conn)
3915 {
3916   struct WildcardData * const wildcard = &(conn->data->wildcard);
3917   CURLcode result = CURLE_OK;
3918
3919   switch (wildcard->state) {
3920   case CURLWC_INIT:
3921     result = init_wc_data(conn);
3922     if(wildcard->state == CURLWC_CLEAN)
3923       /* only listing! */
3924       break;
3925     else
3926       wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
3927     break;
3928
3929   case CURLWC_MATCHING: {
3930     /* In this state is LIST response successfully parsed, so lets restore
3931        previous WRITEFUNCTION callback and WRITEDATA pointer */
3932     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3933     conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3934     conn->data->set.out = ftp_tmp->backup.file_descriptor;
3935     ftp_tmp->backup.write_function = ZERO_NULL;
3936     ftp_tmp->backup.file_descriptor = NULL;
3937     wildcard->state = CURLWC_DOWNLOADING;
3938
3939     if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3940       /* error found in LIST parsing */
3941       wildcard->state = CURLWC_CLEAN;
3942       return wc_statemach(conn);
3943     }
3944     else if(wildcard->filelist->size == 0) {
3945       /* no corresponding file */
3946       wildcard->state = CURLWC_CLEAN;
3947       return CURLE_REMOTE_FILE_NOT_FOUND;
3948     }
3949     return wc_statemach(conn);
3950   }
3951
3952   case CURLWC_DOWNLOADING: {
3953     /* filelist has at least one file, lets get first one */
3954     struct ftp_conn *ftpc = &conn->proto.ftpc;
3955     struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3956
3957     char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3958     if(!tmp_path)
3959       return CURLE_OUT_OF_MEMORY;
3960
3961     /* switch default "state.pathbuffer" and tmp_path, good to see
3962        ftp_parse_url_path function to understand this trick */
3963     Curl_safefree(conn->data->state.pathbuffer);
3964     conn->data->state.pathbuffer = tmp_path;
3965     conn->data->state.path = tmp_path;
3966
3967     infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3968     if(conn->data->set.chunk_bgn) {
3969       long userresponse = conn->data->set.chunk_bgn(
3970           finfo, wildcard->customptr, (int)wildcard->filelist->size);
3971       switch(userresponse) {
3972       case CURL_CHUNK_BGN_FUNC_SKIP:
3973         infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
3974               finfo->filename);
3975         wildcard->state = CURLWC_SKIP;
3976         return wc_statemach(conn);
3977       case CURL_CHUNK_BGN_FUNC_FAIL:
3978         return CURLE_CHUNK_FAILED;
3979       }
3980     }
3981
3982     if(finfo->filetype != CURLFILETYPE_FILE) {
3983       wildcard->state = CURLWC_SKIP;
3984       return wc_statemach(conn);
3985     }
3986
3987     if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
3988       ftpc->known_filesize = finfo->size;
3989
3990     result = ftp_parse_url_path(conn);
3991     if(result)
3992       return result;
3993
3994     /* we don't need the Curl_fileinfo of first file anymore */
3995     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
3996
3997     if(wildcard->filelist->size == 0) { /* remains only one file to down. */
3998       wildcard->state = CURLWC_CLEAN;
3999       /* after that will be ftp_do called once again and no transfer
4000          will be done because of CURLWC_CLEAN state */
4001       return CURLE_OK;
4002     }
4003   } break;
4004
4005   case CURLWC_SKIP: {
4006     if(conn->data->set.chunk_end)
4007       conn->data->set.chunk_end(conn->data->wildcard.customptr);
4008     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4009     wildcard->state = (wildcard->filelist->size == 0) ?
4010                       CURLWC_CLEAN : CURLWC_DOWNLOADING;
4011     return wc_statemach(conn);
4012   }
4013
4014   case CURLWC_CLEAN: {
4015     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
4016     result = CURLE_OK;
4017     if(ftp_tmp)
4018       result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
4019
4020     wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
4021   } break;
4022
4023   case CURLWC_DONE:
4024   case CURLWC_ERROR:
4025     break;
4026   }
4027
4028   return result;
4029 }
4030
4031 /***********************************************************************
4032  *
4033  * ftp_do()
4034  *
4035  * This function is registered as 'curl_do' function. It decodes the path
4036  * parts etc as a wrapper to the actual DO function (ftp_perform).
4037  *
4038  * The input argument is already checked for validity.
4039  */
4040 static CURLcode ftp_do(struct connectdata *conn, bool *done)
4041 {
4042   CURLcode result = CURLE_OK;
4043   struct ftp_conn *ftpc = &conn->proto.ftpc;
4044
4045   *done = FALSE; /* default to false */
4046   ftpc->wait_data_conn = FALSE; /* default to no such wait */
4047
4048   if(conn->data->set.wildcardmatch) {
4049     result = wc_statemach(conn);
4050     if(conn->data->wildcard.state == CURLWC_SKIP ||
4051       conn->data->wildcard.state == CURLWC_DONE) {
4052       /* do not call ftp_regular_transfer */
4053       return CURLE_OK;
4054     }
4055     if(result) /* error, loop or skipping the file */
4056       return result;
4057   }
4058   else { /* no wildcard FSM needed */
4059     result = ftp_parse_url_path(conn);
4060     if(result)
4061       return result;
4062   }
4063
4064   result = ftp_regular_transfer(conn, done);
4065
4066   return result;
4067 }
4068
4069
4070 CURLcode Curl_ftpsendf(struct connectdata *conn,
4071                        const char *fmt, ...)
4072 {
4073   ssize_t bytes_written;
4074 #define SBUF_SIZE 1024
4075   char s[SBUF_SIZE];
4076   size_t write_len;
4077   char *sptr=s;
4078   CURLcode result = CURLE_OK;
4079 #ifdef HAVE_GSSAPI
4080   enum protection_level data_sec = conn->data_prot;
4081 #endif
4082
4083   va_list ap;
4084   va_start(ap, fmt);
4085   write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap);
4086   va_end(ap);
4087
4088   strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
4089   write_len +=2;
4090
4091   bytes_written=0;
4092
4093   result = Curl_convert_to_network(conn->data, s, write_len);
4094   /* Curl_convert_to_network calls failf if unsuccessful */
4095   if(result)
4096     return(result);
4097
4098   for(;;) {
4099 #ifdef HAVE_GSSAPI
4100     conn->data_prot = PROT_CMD;
4101 #endif
4102     result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4103                         &bytes_written);
4104 #ifdef HAVE_GSSAPI
4105     DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4106     conn->data_prot = data_sec;
4107 #endif
4108
4109     if(result)
4110       break;
4111
4112     if(conn->data->set.verbose)
4113       Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4114                  sptr, (size_t)bytes_written, conn);
4115
4116     if(bytes_written != (ssize_t)write_len) {
4117       write_len -= bytes_written;
4118       sptr += bytes_written;
4119     }
4120     else
4121       break;
4122   }
4123
4124   return result;
4125 }
4126
4127 /***********************************************************************
4128  *
4129  * ftp_quit()
4130  *
4131  * This should be called before calling sclose() on an ftp control connection
4132  * (not data connections). We should then wait for the response from the
4133  * server before returning. The calling code should then try to close the
4134  * connection.
4135  *
4136  */
4137 static CURLcode ftp_quit(struct connectdata *conn)
4138 {
4139   CURLcode result = CURLE_OK;
4140
4141   if(conn->proto.ftpc.ctl_valid) {
4142     result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
4143     if(result) {
4144       failf(conn->data, "Failure sending QUIT command: %s",
4145             curl_easy_strerror(result));
4146       conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4147       connclose(conn, "QUIT command failed"); /* mark for connection closure */
4148       state(conn, FTP_STOP);
4149       return result;
4150     }
4151
4152     state(conn, FTP_QUIT);
4153
4154     result = ftp_block_statemach(conn);
4155   }
4156
4157   return result;
4158 }
4159
4160 /***********************************************************************
4161  *
4162  * ftp_disconnect()
4163  *
4164  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4165  * resources. BLOCKING.
4166  */
4167 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4168 {
4169   struct ftp_conn *ftpc= &conn->proto.ftpc;
4170   struct pingpong *pp = &ftpc->pp;
4171
4172   /* We cannot send quit unconditionally. If this connection is stale or
4173      bad in any way, sending quit and waiting around here will make the
4174      disconnect wait in vain and cause more problems than we need to.
4175
4176      ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4177      will try to send the QUIT command, otherwise it will just return.
4178   */
4179   if(dead_connection)
4180     ftpc->ctl_valid = FALSE;
4181
4182   /* The FTP session may or may not have been allocated/setup at this point! */
4183   (void)ftp_quit(conn); /* ignore errors on the QUIT */
4184
4185   if(ftpc->entrypath) {
4186     struct SessionHandle *data = conn->data;
4187     if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4188       data->state.most_recent_ftp_entrypath = NULL;
4189     }
4190     free(ftpc->entrypath);
4191     ftpc->entrypath = NULL;
4192   }
4193
4194   freedirs(ftpc);
4195   if(ftpc->prevpath) {
4196     free(ftpc->prevpath);
4197     ftpc->prevpath = NULL;
4198   }
4199   if(ftpc->server_os) {
4200     free(ftpc->server_os);
4201     ftpc->server_os = NULL;
4202   }
4203
4204   Curl_pp_disconnect(pp);
4205
4206 #ifdef HAVE_GSSAPI
4207   Curl_sec_end(conn);
4208 #endif
4209
4210   return CURLE_OK;
4211 }
4212
4213 /***********************************************************************
4214  *
4215  * ftp_parse_url_path()
4216  *
4217  * Parse the URL path into separate path components.
4218  *
4219  */
4220 static
4221 CURLcode ftp_parse_url_path(struct connectdata *conn)
4222 {
4223   struct SessionHandle *data = conn->data;
4224   /* the ftp struct is already inited in ftp_connect() */
4225   struct FTP *ftp = data->req.protop;
4226   struct ftp_conn *ftpc = &conn->proto.ftpc;
4227   const char *slash_pos;  /* position of the first '/' char in curpos */
4228   const char *path_to_use = data->state.path;
4229   const char *cur_pos;
4230   const char *filename = NULL;
4231
4232   cur_pos = path_to_use; /* current position in path. point at the begin
4233                             of next path component */
4234
4235   ftpc->ctl_valid = FALSE;
4236   ftpc->cwdfail = FALSE;
4237
4238   switch(data->set.ftp_filemethod) {
4239   case FTPFILE_NOCWD:
4240     /* fastest, but less standard-compliant */
4241
4242     /*
4243       The best time to check whether the path is a file or directory is right
4244       here. so:
4245
4246       the first condition in the if() right here, is there just in case
4247       someone decides to set path to NULL one day
4248    */
4249     if(data->state.path &&
4250        data->state.path[0] &&
4251        (data->state.path[strlen(data->state.path) - 1] != '/') )
4252       filename = data->state.path;  /* this is a full file path */
4253       /*
4254         ftpc->file is not used anywhere other than for operations on a file.
4255         In other words, never for directory operations.
4256         So we can safely leave filename as NULL here and use it as a
4257         argument in dir/file decisions.
4258       */
4259     break;
4260
4261   case FTPFILE_SINGLECWD:
4262     /* get the last slash */
4263     if(!path_to_use[0]) {
4264       /* no dir, no file */
4265       ftpc->dirdepth = 0;
4266       break;
4267     }
4268     slash_pos=strrchr(cur_pos, '/');
4269     if(slash_pos || !*cur_pos) {
4270       size_t dirlen = slash_pos-cur_pos;
4271
4272       ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4273       if(!ftpc->dirs)
4274         return CURLE_OUT_OF_MEMORY;
4275
4276       if(!dirlen)
4277         dirlen++;
4278
4279       ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
4280                                          slash_pos ? curlx_uztosi(dirlen) : 1,
4281                                          NULL);
4282       if(!ftpc->dirs[0]) {
4283         freedirs(ftpc);
4284         return CURLE_OUT_OF_MEMORY;
4285       }
4286       ftpc->dirdepth = 1; /* we consider it to be a single dir */
4287       filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4288     }
4289     else
4290       filename = cur_pos;  /* this is a file name only */
4291     break;
4292
4293   default: /* allow pretty much anything */
4294   case FTPFILE_MULTICWD:
4295     ftpc->dirdepth = 0;
4296     ftpc->diralloc = 5; /* default dir depth to allocate */
4297     ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4298     if(!ftpc->dirs)
4299       return CURLE_OUT_OF_MEMORY;
4300
4301     /* we have a special case for listing the root dir only */
4302     if(strequal(path_to_use, "/")) {
4303       cur_pos++; /* make it point to the zero byte */
4304       ftpc->dirs[0] = strdup("/");
4305       ftpc->dirdepth++;
4306     }
4307     else {
4308       /* parse the URL path into separate path components */
4309       while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4310         /* 1 or 0 pointer offset to indicate absolute directory */
4311         ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4312                                 (ftpc->dirdepth == 0))?1:0;
4313
4314         /* seek out the next path component */
4315         if(slash_pos-cur_pos) {
4316           /* we skip empty path components, like "x//y" since the FTP command
4317              CWD requires a parameter and a non-existent parameter a) doesn't
4318              work on many servers and b) has no effect on the others. */
4319           int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
4320           ftpc->dirs[ftpc->dirdepth] =
4321             curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
4322           if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
4323             failf(data, "no memory");
4324             freedirs(ftpc);
4325             return CURLE_OUT_OF_MEMORY;
4326           }
4327           if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
4328             free(ftpc->dirs[ftpc->dirdepth]);
4329             freedirs(ftpc);
4330             return CURLE_URL_MALFORMAT;
4331           }
4332         }
4333         else {
4334           cur_pos = slash_pos + 1; /* jump to the rest of the string */
4335           if(!ftpc->dirdepth) {
4336             /* path starts with a slash, add that as a directory */
4337             ftpc->dirs[ftpc->dirdepth] = strdup("/");
4338             if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
4339               failf(data, "no memory");
4340               freedirs(ftpc);
4341               return CURLE_OUT_OF_MEMORY;
4342             }
4343           }
4344           continue;
4345         }
4346
4347         cur_pos = slash_pos + 1; /* jump to the rest of the string */
4348         if(++ftpc->dirdepth >= ftpc->diralloc) {
4349           /* enlarge array */
4350           char **bigger;
4351           ftpc->diralloc *= 2; /* double the size each time */
4352           bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4353           if(!bigger) {
4354             freedirs(ftpc);
4355             return CURLE_OUT_OF_MEMORY;
4356           }
4357           ftpc->dirs = bigger;
4358         }
4359       }
4360     }
4361     filename = cur_pos;  /* the rest is the file name */
4362     break;
4363   } /* switch */
4364
4365   if(filename && *filename) {
4366     ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
4367     if(NULL == ftpc->file) {
4368       freedirs(ftpc);
4369       failf(data, "no memory");
4370       return CURLE_OUT_OF_MEMORY;
4371     }
4372     if(isBadFtpString(ftpc->file)) {
4373       freedirs(ftpc);
4374       return CURLE_URL_MALFORMAT;
4375     }
4376   }
4377   else
4378     ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4379                        pointer */
4380
4381   if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4382     /* We need a file name when uploading. Return error! */
4383     failf(data, "Uploading to a URL without a file name!");
4384     return CURLE_URL_MALFORMAT;
4385   }
4386
4387   ftpc->cwddone = FALSE; /* default to not done */
4388
4389   if(ftpc->prevpath) {
4390     /* prevpath is "raw" so we convert the input path before we compare the
4391        strings */
4392     int dlen;
4393     char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4394     if(!path) {
4395       freedirs(ftpc);
4396       return CURLE_OUT_OF_MEMORY;
4397     }
4398
4399     dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
4400     if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
4401        strnequal(path, ftpc->prevpath, dlen)) {
4402       infof(data, "Request has same path as previous transfer\n");
4403       ftpc->cwddone = TRUE;
4404     }
4405     free(path);
4406   }
4407
4408   return CURLE_OK;
4409 }
4410
4411 /* call this when the DO phase has completed */
4412 static CURLcode ftp_dophase_done(struct connectdata *conn,
4413                                  bool connected)
4414 {
4415   struct FTP *ftp = conn->data->req.protop;
4416   struct ftp_conn *ftpc = &conn->proto.ftpc;
4417
4418   if(connected) {
4419     int completed;
4420     CURLcode result = ftp_do_more(conn, &completed);
4421
4422     if(result) {
4423       if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
4424         /* close the second socket if it was created already */
4425         Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
4426         conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4427       }
4428       return result;
4429     }
4430   }
4431
4432   if(ftp->transfer != FTPTRANSFER_BODY)
4433     /* no data to transfer */
4434     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4435   else if(!connected)
4436     /* since we didn't connect now, we want do_more to get called */
4437     conn->bits.do_more = TRUE;
4438
4439   ftpc->ctl_valid = TRUE; /* seems good */
4440
4441   return CURLE_OK;
4442 }
4443
4444 /* called from multi.c while DOing */
4445 static CURLcode ftp_doing(struct connectdata *conn,
4446                           bool *dophase_done)
4447 {
4448   CURLcode result = ftp_multi_statemach(conn, dophase_done);
4449
4450   if(result)
4451     DEBUGF(infof(conn->data, "DO phase failed\n"));
4452   else if(*dophase_done) {
4453     result = ftp_dophase_done(conn, FALSE /* not connected */);
4454
4455     DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4456   }
4457   return result;
4458 }
4459
4460 /***********************************************************************
4461  *
4462  * ftp_regular_transfer()
4463  *
4464  * The input argument is already checked for validity.
4465  *
4466  * Performs all commands done before a regular transfer between a local and a
4467  * remote host.
4468  *
4469  * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4470  * ftp_done() function without finding any major problem.
4471  */
4472 static
4473 CURLcode ftp_regular_transfer(struct connectdata *conn,
4474                               bool *dophase_done)
4475 {
4476   CURLcode result=CURLE_OK;
4477   bool connected=FALSE;
4478   struct SessionHandle *data = conn->data;
4479   struct ftp_conn *ftpc = &conn->proto.ftpc;
4480   data->req.size = -1; /* make sure this is unknown at this point */
4481
4482   Curl_pgrsSetUploadCounter(data, 0);
4483   Curl_pgrsSetDownloadCounter(data, 0);
4484   Curl_pgrsSetUploadSize(data, -1);
4485   Curl_pgrsSetDownloadSize(data, -1);
4486
4487   ftpc->ctl_valid = TRUE; /* starts good */
4488
4489   result = ftp_perform(conn,
4490                        &connected, /* have we connected after PASV/PORT */
4491                        dophase_done); /* all commands in the DO-phase done? */
4492
4493   if(!result) {
4494
4495     if(!*dophase_done)
4496       /* the DO phase has not completed yet */
4497       return CURLE_OK;
4498
4499     result = ftp_dophase_done(conn, connected);
4500
4501     if(result)
4502       return result;
4503   }
4504   else
4505     freedirs(ftpc);
4506
4507   return result;
4508 }
4509
4510 static CURLcode ftp_setup_connection(struct connectdata *conn)
4511 {
4512   struct SessionHandle *data = conn->data;
4513   char *type;
4514   char command;
4515   struct FTP *ftp;
4516
4517   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4518     /* Unless we have asked to tunnel ftp operations through the proxy, we
4519        switch and use HTTP operations only */
4520 #ifndef CURL_DISABLE_HTTP
4521     if(conn->handler == &Curl_handler_ftp)
4522       conn->handler = &Curl_handler_ftp_proxy;
4523     else {
4524 #ifdef USE_SSL
4525       conn->handler = &Curl_handler_ftps_proxy;
4526 #else
4527       failf(data, "FTPS not supported!");
4528       return CURLE_UNSUPPORTED_PROTOCOL;
4529 #endif
4530     }
4531     /* set it up as a HTTP connection instead */
4532     return conn->handler->setup_connection(conn);
4533 #else
4534     failf(data, "FTP over http proxy requires HTTP support built-in!");
4535     return CURLE_UNSUPPORTED_PROTOCOL;
4536 #endif
4537   }
4538
4539   conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
4540   if(NULL == ftp)
4541     return CURLE_OUT_OF_MEMORY;
4542
4543   data->state.path++;   /* don't include the initial slash */
4544   data->state.slash_removed = TRUE; /* we've skipped the slash */
4545
4546   /* FTP URLs support an extension like ";type=<typecode>" that
4547    * we'll try to get now! */
4548   type = strstr(data->state.path, ";type=");
4549
4550   if(!type)
4551     type = strstr(conn->host.rawalloc, ";type=");
4552
4553   if(type) {
4554     *type = 0;                     /* it was in the middle of the hostname */
4555     command = Curl_raw_toupper(type[6]);
4556     conn->bits.type_set = TRUE;
4557
4558     switch (command) {
4559     case 'A': /* ASCII mode */
4560       data->set.prefer_ascii = TRUE;
4561       break;
4562
4563     case 'D': /* directory mode */
4564       data->set.ftp_list_only = TRUE;
4565       break;
4566
4567     case 'I': /* binary mode */
4568     default:
4569       /* switch off ASCII */
4570       data->set.prefer_ascii = FALSE;
4571       break;
4572     }
4573   }
4574
4575   /* get some initial data into the ftp struct */
4576   ftp->bytecountp = &conn->data->req.bytecount;
4577   ftp->transfer = FTPTRANSFER_BODY;
4578   ftp->downloadsize = 0;
4579
4580   /* No need to duplicate user+password, the connectdata struct won't change
4581      during a session, but we re-init them here since on subsequent inits
4582      since the conn struct may have changed or been replaced.
4583   */
4584   ftp->user = conn->user;
4585   ftp->passwd = conn->passwd;
4586   if(isBadFtpString(ftp->user))
4587     return CURLE_URL_MALFORMAT;
4588   if(isBadFtpString(ftp->passwd))
4589     return CURLE_URL_MALFORMAT;
4590
4591   conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
4592
4593   return CURLE_OK;
4594 }
4595
4596 #endif /* CURL_DISABLE_FTP */