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