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