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