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