connect: treat an interface bindlocal() problem as a non-fatal error
[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 will be in FTP_STOP state and then we wait
882      for the secondary socket to become writeable. If we're in another state,
883      we're still handling commands on the control (primary) connection.
884
885   */
886
887   switch(ftpc->state) {
888   case FTP_STOP:
889     break;
890   default:
891     return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
892   }
893
894   socks[0] = conn->sock[SECONDARYSOCKET];
895   if(ftpc->wait_data_conn) {
896     socks[1] = conn->sock[FIRSTSOCKET];
897     return GETSOCK_READSOCK(0) | GETSOCK_READSOCK(1);
898   }
899
900   return GETSOCK_READSOCK(0);
901 }
902
903 /* This is called after the FTP_QUOTE state is passed.
904
905    ftp_state_cwd() sends the range of CWD commands to the server to change to
906    the correct directory. It may also need to send MKD commands to create
907    missing ones, if that option is enabled.
908 */
909 static CURLcode ftp_state_cwd(struct connectdata *conn)
910 {
911   CURLcode result = CURLE_OK;
912   struct ftp_conn *ftpc = &conn->proto.ftpc;
913
914   if(ftpc->cwddone)
915     /* already done and fine */
916     result = ftp_state_post_cwd(conn);
917   else {
918     ftpc->count2 = 0; /* count2 counts failed CWDs */
919
920     /* count3 is set to allow a MKD to fail once. In the case when first CWD
921        fails and then MKD fails (due to another session raced it to create the
922        dir) this then allows for a second try to CWD to it */
923     ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
924
925     if(conn->bits.reuse && ftpc->entrypath) {
926       /* This is a re-used connection. Since we change directory to where the
927          transfer is taking place, we must first get back to the original dir
928          where we ended up after login: */
929       ftpc->count1 = 0; /* we count this as the first path, then we add one
930                           for all upcoming ones in the ftp->dirs[] array */
931       PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
932       state(conn, FTP_CWD);
933     }
934     else {
935       if(ftpc->dirdepth) {
936         ftpc->count1 = 1;
937         /* issue the first CWD, the rest is sent when the CWD responses are
938            received... */
939         PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
940         state(conn, FTP_CWD);
941       }
942       else {
943         /* No CWD necessary */
944         result = ftp_state_post_cwd(conn);
945       }
946     }
947   }
948   return result;
949 }
950
951 typedef enum {
952   EPRT,
953   PORT,
954   DONE
955 } ftpport;
956
957 static CURLcode ftp_state_use_port(struct connectdata *conn,
958                                    ftpport fcmd) /* start with this */
959
960 {
961   CURLcode result = CURLE_OK;
962   struct ftp_conn *ftpc = &conn->proto.ftpc;
963   struct SessionHandle *data=conn->data;
964   curl_socket_t portsock= CURL_SOCKET_BAD;
965   char myhost[256] = "";
966
967   struct Curl_sockaddr_storage ss;
968   Curl_addrinfo *res, *ai;
969   curl_socklen_t sslen;
970   char hbuf[NI_MAXHOST];
971   struct sockaddr *sa=(struct sockaddr *)&ss;
972   struct sockaddr_in * const sa4 = (void *)sa;
973 #ifdef ENABLE_IPV6
974   struct sockaddr_in6 * const sa6 = (void *)sa;
975 #endif
976   char tmp[1024];
977   static const char mode[][5] = { "EPRT", "PORT" };
978   int rc;
979   int error;
980   char *host = NULL;
981   char *string_ftpport = data->set.str[STRING_FTPPORT];
982   struct Curl_dns_entry *h=NULL;
983   unsigned short port_min = 0;
984   unsigned short port_max = 0;
985   unsigned short port;
986   bool possibly_non_local = TRUE;
987
988   char *addr = NULL;
989
990   /* Step 1, figure out what is requested,
991    * accepted format :
992    * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
993    */
994
995   if(data->set.str[STRING_FTPPORT] &&
996      (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
997
998 #ifdef ENABLE_IPV6
999     size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
1000       INET6_ADDRSTRLEN : strlen(string_ftpport);
1001 #else
1002     size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
1003       INET_ADDRSTRLEN : strlen(string_ftpport);
1004 #endif
1005     char *ip_start = string_ftpport;
1006     char *ip_end = NULL;
1007     char *port_start = NULL;
1008     char *port_sep = NULL;
1009
1010     addr = calloc(addrlen+1, 1);
1011     if(!addr)
1012       return CURLE_OUT_OF_MEMORY;
1013
1014 #ifdef ENABLE_IPV6
1015     if(*string_ftpport == '[') {
1016       /* [ipv6]:port(-range) */
1017       ip_start = string_ftpport + 1;
1018       if((ip_end = strchr(string_ftpport, ']')) != NULL )
1019         strncpy(addr, ip_start, ip_end - ip_start);
1020     }
1021     else
1022 #endif
1023       if(*string_ftpport == ':') {
1024         /* :port */
1025         ip_end = string_ftpport;
1026     }
1027     else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
1028         /* either ipv6 or (ipv4|domain|interface):port(-range) */
1029 #ifdef ENABLE_IPV6
1030       if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
1031         /* ipv6 */
1032         port_min = port_max = 0;
1033         strcpy(addr, string_ftpport);
1034         ip_end = NULL; /* this got no port ! */
1035       }
1036       else
1037 #endif
1038         /* (ipv4|domain|interface):port(-range) */
1039         strncpy(addr, string_ftpport, ip_end - ip_start );
1040     }
1041     else
1042       /* ipv4|interface */
1043       strcpy(addr, string_ftpport);
1044
1045     /* parse the port */
1046     if(ip_end != NULL) {
1047       if((port_start = strchr(ip_end, ':')) != NULL) {
1048         port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
1049         if((port_sep = strchr(port_start, '-')) != NULL) {
1050           port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
1051         }
1052         else
1053           port_max = port_min;
1054       }
1055     }
1056
1057     /* correct errors like:
1058      *  :1234-1230
1059      *  :-4711 , in this case port_min is (unsigned)-1,
1060      *           therefore port_min > port_max for all cases
1061      *           but port_max = (unsigned)-1
1062      */
1063     if(port_min > port_max )
1064       port_min = port_max = 0;
1065
1066
1067     if(*addr != '\0') {
1068       /* attempt to get the address of the given interface name */
1069       switch(Curl_if2ip(conn->ip_addr->ai_family, conn->scope, addr,
1070                      hbuf, sizeof(hbuf))) {
1071         case IF2IP_NOT_FOUND:
1072           /* not an interface, use the given string as host name instead */
1073           host = addr;
1074           break;
1075         case IF2IP_AF_NOT_SUPPORTED:
1076           return CURLE_FTP_PORT_FAILED;
1077         case IF2IP_FOUND:
1078           host = hbuf; /* use the hbuf for host name */
1079       }
1080     }
1081     else
1082       /* there was only a port(-range) given, default the host */
1083       host = NULL;
1084   } /* data->set.ftpport */
1085
1086   if(!host) {
1087     /* not an interface and not a host name, get default by extracting
1088        the IP from the control connection */
1089
1090     sslen = sizeof(ss);
1091     if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1092       failf(data, "getsockname() failed: %s",
1093           Curl_strerror(conn, SOCKERRNO) );
1094       Curl_safefree(addr);
1095       return CURLE_FTP_PORT_FAILED;
1096     }
1097     switch(sa->sa_family) {
1098 #ifdef ENABLE_IPV6
1099     case AF_INET6:
1100       Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
1101       break;
1102 #endif
1103     default:
1104       Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
1105       break;
1106     }
1107     host = hbuf; /* use this host name */
1108     possibly_non_local = FALSE; /* we know it is local now */
1109   }
1110
1111   /* resolv ip/host to ip */
1112   rc = Curl_resolv(conn, host, 0, &h);
1113   if(rc == CURLRESOLV_PENDING)
1114     (void)Curl_resolver_wait_resolv(conn, &h);
1115   if(h) {
1116     res = h->addr;
1117     /* when we return from this function, we can forget about this entry
1118        to we can unlock it now already */
1119     Curl_resolv_unlock(data, h);
1120   } /* (h) */
1121   else
1122     res = NULL; /* failure! */
1123
1124   if(res == NULL) {
1125     failf(data, "failed to resolve the address provided to PORT: %s", host);
1126     Curl_safefree(addr);
1127     return CURLE_FTP_PORT_FAILED;
1128   }
1129
1130   Curl_safefree(addr);
1131   host = NULL;
1132
1133   /* step 2, create a socket for the requested address */
1134
1135   portsock = CURL_SOCKET_BAD;
1136   error = 0;
1137   for(ai = res; ai; ai = ai->ai_next) {
1138     result = Curl_socket(conn, ai, NULL, &portsock);
1139     if(result) {
1140       error = SOCKERRNO;
1141       continue;
1142     }
1143     break;
1144   }
1145   if(!ai) {
1146     failf(data, "socket failure: %s", Curl_strerror(conn, error));
1147     return CURLE_FTP_PORT_FAILED;
1148   }
1149
1150   /* step 3, bind to a suitable local address */
1151
1152   memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1153   sslen = ai->ai_addrlen;
1154
1155   for(port = port_min; port <= port_max;) {
1156     if(sa->sa_family == AF_INET)
1157       sa4->sin_port = htons(port);
1158 #ifdef ENABLE_IPV6
1159     else
1160       sa6->sin6_port = htons(port);
1161 #endif
1162     /* Try binding the given address. */
1163     if(bind(portsock, sa, sslen) ) {
1164       /* It failed. */
1165       error = SOCKERRNO;
1166       if(possibly_non_local && (error == EADDRNOTAVAIL)) {
1167         /* The requested bind address is not local.  Use the address used for
1168          * the control connection instead and restart the port loop
1169          */
1170
1171         infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
1172               Curl_strerror(conn, error) );
1173
1174         sslen = sizeof(ss);
1175         if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
1176           failf(data, "getsockname() failed: %s",
1177                 Curl_strerror(conn, SOCKERRNO) );
1178           Curl_closesocket(conn, portsock);
1179           return CURLE_FTP_PORT_FAILED;
1180         }
1181         port = port_min;
1182         possibly_non_local = FALSE; /* don't try this again */
1183         continue;
1184       }
1185       else if(error != EADDRINUSE && error != EACCES) {
1186         failf(data, "bind(port=%hu) failed: %s", port,
1187               Curl_strerror(conn, error) );
1188         Curl_closesocket(conn, portsock);
1189         return CURLE_FTP_PORT_FAILED;
1190       }
1191     }
1192     else
1193       break;
1194
1195     port++;
1196   }
1197
1198   /* maybe all ports were in use already*/
1199   if(port > port_max) {
1200     failf(data, "bind() failed, we ran out of ports!");
1201     Curl_closesocket(conn, portsock);
1202     return CURLE_FTP_PORT_FAILED;
1203   }
1204
1205   /* get the name again after the bind() so that we can extract the
1206      port number it uses now */
1207   sslen = sizeof(ss);
1208   if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
1209     failf(data, "getsockname() failed: %s",
1210           Curl_strerror(conn, SOCKERRNO) );
1211     Curl_closesocket(conn, portsock);
1212     return CURLE_FTP_PORT_FAILED;
1213   }
1214
1215   /* step 4, listen on the socket */
1216
1217   if(listen(portsock, 1)) {
1218     failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
1219     Curl_closesocket(conn, portsock);
1220     return CURLE_FTP_PORT_FAILED;
1221   }
1222
1223   /* step 5, send the proper FTP command */
1224
1225   /* get a plain printable version of the numerical address to work with
1226      below */
1227   Curl_printable_address(ai, myhost, sizeof(myhost));
1228
1229 #ifdef ENABLE_IPV6
1230   if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
1231     /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
1232        request and enable EPRT again! */
1233     conn->bits.ftp_use_eprt = TRUE;
1234 #endif
1235
1236   for(; fcmd != DONE; fcmd++) {
1237
1238     if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
1239       /* if disabled, goto next */
1240       continue;
1241
1242     if((PORT == fcmd) && sa->sa_family != AF_INET)
1243       /* PORT is ipv4 only */
1244       continue;
1245
1246     switch (sa->sa_family) {
1247     case AF_INET:
1248       port = ntohs(sa4->sin_port);
1249       break;
1250 #ifdef ENABLE_IPV6
1251     case AF_INET6:
1252       port = ntohs(sa6->sin6_port);
1253       break;
1254 #endif
1255     default:
1256       continue; /* might as well skip this */
1257     }
1258
1259     if(EPRT == fcmd) {
1260       /*
1261        * Two fine examples from RFC2428;
1262        *
1263        * EPRT |1|132.235.1.2|6275|
1264        *
1265        * EPRT |2|1080::8:800:200C:417A|5282|
1266        */
1267
1268       result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
1269                              sa->sa_family == AF_INET?1:2,
1270                              myhost, port);
1271       if(result) {
1272         failf(data, "Failure sending EPRT command: %s",
1273               curl_easy_strerror(result));
1274         Curl_closesocket(conn, portsock);
1275         /* don't retry using PORT */
1276         ftpc->count1 = PORT;
1277         /* bail out */
1278         state(conn, FTP_STOP);
1279         return result;
1280       }
1281       break;
1282     }
1283     else if(PORT == fcmd) {
1284       char *source = myhost;
1285       char *dest = tmp;
1286
1287       /* translate x.x.x.x to x,x,x,x */
1288       while(source && *source) {
1289         if(*source == '.')
1290           *dest=',';
1291         else
1292           *dest = *source;
1293         dest++;
1294         source++;
1295       }
1296       *dest = 0;
1297       snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
1298
1299       result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
1300       if(result) {
1301         failf(data, "Failure sending PORT command: %s",
1302               curl_easy_strerror(result));
1303         Curl_closesocket(conn, portsock);
1304         /* bail out */
1305         state(conn, FTP_STOP);
1306         return result;
1307       }
1308       break;
1309     }
1310   }
1311
1312   /* store which command was sent */
1313   ftpc->count1 = fcmd;
1314
1315   /* we set the secondary socket variable to this for now, it is only so that
1316      the cleanup function will close it in case we fail before the true
1317      secondary stuff is made */
1318   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
1319     Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
1320   conn->sock[SECONDARYSOCKET] = portsock;
1321
1322   /* this tcpconnect assignment below is a hackish work-around to make the
1323      multi interface with active FTP work - as it will not wait for a
1324      (passive) connect in Curl_is_connected().
1325
1326      The *proper* fix is to make sure that the active connection from the
1327      server is done in a non-blocking way. Currently, it is still BLOCKING.
1328   */
1329   conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
1330
1331   state(conn, FTP_PORT);
1332   return result;
1333 }
1334
1335 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1336 {
1337   struct ftp_conn *ftpc = &conn->proto.ftpc;
1338   CURLcode result = CURLE_OK;
1339   /*
1340     Here's the excecutive summary on what to do:
1341
1342     PASV is RFC959, expect:
1343     227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
1344
1345     LPSV is RFC1639, expect:
1346     228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
1347
1348     EPSV is RFC2428, expect:
1349     229 Entering Extended Passive Mode (|||port|)
1350
1351   */
1352
1353   static const char mode[][5] = { "EPSV", "PASV" };
1354   int modeoff;
1355
1356 #ifdef PF_INET6
1357   if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
1358     /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
1359        request and enable EPSV again! */
1360     conn->bits.ftp_use_epsv = TRUE;
1361 #endif
1362
1363   modeoff = conn->bits.ftp_use_epsv?0:1;
1364
1365   PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
1366
1367   ftpc->count1 = modeoff;
1368   state(conn, FTP_PASV);
1369   infof(conn->data, "Connect data stream passively\n");
1370
1371   return result;
1372 }
1373
1374 /* REST is the last command in the chain of commands when a "head"-like
1375    request is made. Thus, if an actual transfer is to be made this is where
1376    we take off for real. */
1377 static CURLcode ftp_state_post_rest(struct connectdata *conn)
1378 {
1379   CURLcode result = CURLE_OK;
1380   struct FTP *ftp = conn->data->state.proto.ftp;
1381   struct SessionHandle *data = conn->data;
1382
1383   if(ftp->transfer != FTPTRANSFER_BODY) {
1384     /* doesn't transfer any data */
1385
1386     /* still possibly do PRE QUOTE jobs */
1387     state(conn, FTP_RETR_PREQUOTE);
1388     result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1389   }
1390   else if(data->set.ftp_use_port) {
1391     /* We have chosen to use the PORT (or similar) command */
1392     result = ftp_state_use_port(conn, EPRT);
1393   }
1394   else {
1395     /* We have chosen (this is default) to use the PASV (or similar) command */
1396     if(data->set.ftp_use_pret) {
1397       /* The user has requested that we send a PRET command
1398          to prepare the server for the upcoming PASV */
1399       if(!conn->proto.ftpc.file) {
1400         PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
1401                 data->set.str[STRING_CUSTOMREQUEST]?
1402                 data->set.str[STRING_CUSTOMREQUEST]:
1403                 (data->set.ftp_list_only?"NLST":"LIST"));
1404       }
1405       else if(data->set.upload) {
1406         PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
1407       }
1408       else {
1409         PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
1410       }
1411       state(conn, FTP_PRET);
1412     }
1413     else {
1414       result = ftp_state_use_pasv(conn);
1415     }
1416   }
1417   return result;
1418 }
1419
1420 static CURLcode ftp_state_post_size(struct connectdata *conn)
1421 {
1422   CURLcode result = CURLE_OK;
1423   struct FTP *ftp = conn->data->state.proto.ftp;
1424   struct ftp_conn *ftpc = &conn->proto.ftpc;
1425
1426   if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
1427     /* if a "head"-like request is being made (on a file) */
1428
1429     /* Determine if server can respond to REST command and therefore
1430        whether it supports range */
1431     PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
1432
1433     state(conn, FTP_REST);
1434   }
1435   else
1436     result = ftp_state_post_rest(conn);
1437
1438   return result;
1439 }
1440
1441 static CURLcode ftp_state_post_type(struct connectdata *conn)
1442 {
1443   CURLcode result = CURLE_OK;
1444   struct FTP *ftp = conn->data->state.proto.ftp;
1445   struct ftp_conn *ftpc = &conn->proto.ftpc;
1446
1447   if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
1448     /* if a "head"-like request is being made (on a file) */
1449
1450     /* we know ftpc->file is a valid pointer to a file name */
1451     PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1452
1453     state(conn, FTP_SIZE);
1454   }
1455   else
1456     result = ftp_state_post_size(conn);
1457
1458   return result;
1459 }
1460
1461 static CURLcode ftp_state_post_listtype(struct connectdata *conn)
1462 {
1463   CURLcode result = CURLE_OK;
1464   struct SessionHandle *data = conn->data;
1465
1466   /* If this output is to be machine-parsed, the NLST command might be better
1467      to use, since the LIST command output is not specified or standard in any
1468      way. It has turned out that the NLST list output is not the same on all
1469      servers either... */
1470
1471   /*
1472      if FTPFILE_NOCWD was specified, we are currently in
1473      the user's home directory, so we should add the path
1474      as argument for the LIST / NLST / or custom command.
1475      Whether the server will support this, is uncertain.
1476
1477      The other ftp_filemethods will CWD into dir/dir/ first and
1478      then just do LIST (in that case: nothing to do here)
1479   */
1480   char *cmd,*lstArg,*slashPos;
1481
1482   lstArg = NULL;
1483   if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
1484      data->state.path &&
1485      data->state.path[0] &&
1486      strchr(data->state.path,'/')) {
1487
1488     lstArg = strdup(data->state.path);
1489     if(!lstArg)
1490       return CURLE_OUT_OF_MEMORY;
1491
1492     /* Check if path does not end with /, as then we cut off the file part */
1493     if(lstArg[strlen(lstArg) - 1] != '/')  {
1494
1495       /* chop off the file part if format is dir/dir/file */
1496       slashPos = strrchr(lstArg,'/');
1497       if(slashPos)
1498         *(slashPos+1) = '\0';
1499     }
1500   }
1501
1502   cmd = aprintf( "%s%s%s",
1503                  data->set.str[STRING_CUSTOMREQUEST]?
1504                  data->set.str[STRING_CUSTOMREQUEST]:
1505                  (data->set.ftp_list_only?"NLST":"LIST"),
1506                  lstArg? " ": "",
1507                  lstArg? lstArg: "" );
1508
1509   if(!cmd) {
1510     if(lstArg)
1511       free(lstArg);
1512     return CURLE_OUT_OF_MEMORY;
1513   }
1514
1515   result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
1516
1517   if(lstArg)
1518     free(lstArg);
1519
1520   free(cmd);
1521
1522   if(result != CURLE_OK)
1523     return result;
1524
1525   state(conn, FTP_LIST);
1526
1527   return result;
1528 }
1529
1530 static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
1531 {
1532   CURLcode result = CURLE_OK;
1533
1534   /* We've sent the TYPE, now we must send the list of prequote strings */
1535
1536   result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1537
1538   return result;
1539 }
1540
1541 static CURLcode ftp_state_post_stortype(struct connectdata *conn)
1542 {
1543   CURLcode result = CURLE_OK;
1544
1545   /* We've sent the TYPE, now we must send the list of prequote strings */
1546
1547   result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
1548
1549   return result;
1550 }
1551
1552 static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
1553 {
1554   CURLcode result = CURLE_OK;
1555   struct FTP *ftp = conn->data->state.proto.ftp;
1556   struct SessionHandle *data = conn->data;
1557   struct ftp_conn *ftpc = &conn->proto.ftpc;
1558
1559   /* If we have selected NOBODY and HEADER, it means that we only want file
1560      information. Which in FTP can't be much more than the file size and
1561      date. */
1562   if(data->set.opt_no_body && ftpc->file &&
1563      ftp_need_type(conn, data->set.prefer_ascii)) {
1564     /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1565        may not support it! It is however the only way we have to get a file's
1566        size! */
1567
1568     ftp->transfer = FTPTRANSFER_INFO;
1569     /* this means no actual transfer will be made */
1570
1571     /* Some servers return different sizes for different modes, and thus we
1572        must set the proper type before we check the size */
1573     result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
1574     if(result)
1575       return result;
1576   }
1577   else
1578     result = ftp_state_post_type(conn);
1579
1580   return result;
1581 }
1582
1583 /* This is called after the CWD commands have been done in the beginning of
1584    the DO phase */
1585 static CURLcode ftp_state_post_cwd(struct connectdata *conn)
1586 {
1587   CURLcode result = CURLE_OK;
1588   struct SessionHandle *data = conn->data;
1589   struct ftp_conn *ftpc = &conn->proto.ftpc;
1590
1591   /* Requested time of file or time-depended transfer? */
1592   if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
1593
1594     /* we have requested to get the modified-time of the file, this is a white
1595        spot as the MDTM is not mentioned in RFC959 */
1596     PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
1597
1598     state(conn, FTP_MDTM);
1599   }
1600   else
1601     result = ftp_state_post_mdtm(conn);
1602
1603   return result;
1604 }
1605
1606
1607 /* This is called after the TYPE and possible quote commands have been sent */
1608 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
1609                                    bool sizechecked)
1610 {
1611   CURLcode result = CURLE_OK;
1612   struct FTP *ftp = conn->data->state.proto.ftp;
1613   struct SessionHandle *data = conn->data;
1614   struct ftp_conn *ftpc = &conn->proto.ftpc;
1615   int seekerr = CURL_SEEKFUNC_OK;
1616
1617   if((data->state.resume_from && !sizechecked) ||
1618      ((data->state.resume_from > 0) && sizechecked)) {
1619     /* we're about to continue the uploading of a file */
1620     /* 1. get already existing file's size. We use the SIZE command for this
1621        which may not exist in the server!  The SIZE command is not in
1622        RFC959. */
1623
1624     /* 2. This used to set REST. But since we can do append, we
1625        don't another ftp command. We just skip the source file
1626        offset and then we APPEND the rest on the file instead */
1627
1628     /* 3. pass file-size number of bytes in the source file */
1629     /* 4. lower the infilesize counter */
1630     /* => transfer as usual */
1631
1632     if(data->state.resume_from < 0 ) {
1633       /* Got no given size to start from, figure it out */
1634       PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1635       state(conn, FTP_STOR_SIZE);
1636       return result;
1637     }
1638
1639     /* enable append */
1640     data->set.ftp_append = TRUE;
1641
1642     /* Let's read off the proper amount of bytes from the input. */
1643     if(conn->seek_func) {
1644       seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
1645                                 SEEK_SET);
1646     }
1647
1648     if(seekerr != CURL_SEEKFUNC_OK) {
1649       if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
1650         failf(data, "Could not seek stream");
1651         return CURLE_FTP_COULDNT_USE_REST;
1652       }
1653       /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
1654       else {
1655         curl_off_t passed=0;
1656         do {
1657           size_t readthisamountnow =
1658             (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
1659             BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
1660
1661           size_t actuallyread =
1662             conn->fread_func(data->state.buffer, 1, readthisamountnow,
1663                              conn->fread_in);
1664
1665           passed += actuallyread;
1666           if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
1667             /* this checks for greater-than only to make sure that the
1668                CURL_READFUNC_ABORT return code still aborts */
1669             failf(data, "Failed to read data");
1670             return CURLE_FTP_COULDNT_USE_REST;
1671           }
1672         } while(passed < data->state.resume_from);
1673       }
1674     }
1675     /* now, decrease the size of the read */
1676     if(data->set.infilesize>0) {
1677       data->set.infilesize -= data->state.resume_from;
1678
1679       if(data->set.infilesize <= 0) {
1680         infof(data, "File already completely uploaded\n");
1681
1682         /* no data to transfer */
1683         Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1684
1685         /* Set ->transfer so that we won't get any error in
1686          * ftp_done() because we didn't transfer anything! */
1687         ftp->transfer = FTPTRANSFER_NONE;
1688
1689         state(conn, FTP_STOP);
1690         return CURLE_OK;
1691       }
1692     }
1693     /* we've passed, proceed as normal */
1694   } /* resume_from */
1695
1696   PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
1697           ftpc->file);
1698
1699   state(conn, FTP_STOR);
1700
1701   return result;
1702 }
1703
1704 static CURLcode ftp_state_quote(struct connectdata *conn,
1705                                 bool init,
1706                                 ftpstate instate)
1707 {
1708   CURLcode result = CURLE_OK;
1709   struct SessionHandle *data = conn->data;
1710   struct FTP *ftp = data->state.proto.ftp;
1711   struct ftp_conn *ftpc = &conn->proto.ftpc;
1712   bool quote=FALSE;
1713   struct curl_slist *item;
1714
1715   switch(instate) {
1716   case FTP_QUOTE:
1717   default:
1718     item = data->set.quote;
1719     break;
1720   case FTP_RETR_PREQUOTE:
1721   case FTP_STOR_PREQUOTE:
1722     item = data->set.prequote;
1723     break;
1724   case FTP_POSTQUOTE:
1725     item = data->set.postquote;
1726     break;
1727   }
1728
1729   /*
1730    * This state uses:
1731    * 'count1' to iterate over the commands to send
1732    * 'count2' to store wether to allow commands to fail
1733    */
1734
1735   if(init)
1736     ftpc->count1 = 0;
1737   else
1738     ftpc->count1++;
1739
1740   if(item) {
1741     int i = 0;
1742
1743     /* Skip count1 items in the linked list */
1744     while((i< ftpc->count1) && item) {
1745       item = item->next;
1746       i++;
1747     }
1748     if(item) {
1749       char *cmd = item->data;
1750       if(cmd[0] == '*') {
1751         cmd++;
1752         ftpc->count2 = 1; /* the sent command is allowed to fail */
1753       }
1754       else
1755         ftpc->count2 = 0; /* failure means cancel operation */
1756
1757       PPSENDF(&ftpc->pp, "%s", cmd);
1758       state(conn, instate);
1759       quote = TRUE;
1760     }
1761   }
1762
1763   if(!quote) {
1764     /* No more quote to send, continue to ... */
1765     switch(instate) {
1766     case FTP_QUOTE:
1767     default:
1768       result = ftp_state_cwd(conn);
1769       break;
1770     case FTP_RETR_PREQUOTE:
1771       if(ftp->transfer != FTPTRANSFER_BODY)
1772         state(conn, FTP_STOP);
1773       else {
1774         if(ftpc->known_filesize != -1) {
1775           Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
1776           result = ftp_state_post_retr_size(conn, ftpc->known_filesize);
1777         }
1778         else {
1779           PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
1780           state(conn, FTP_RETR_SIZE);
1781         }
1782       }
1783       break;
1784     case FTP_STOR_PREQUOTE:
1785       result = ftp_state_ul_setup(conn, FALSE);
1786       break;
1787     case FTP_POSTQUOTE:
1788       break;
1789     }
1790   }
1791
1792   return result;
1793 }
1794
1795 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
1796    problems */
1797 static CURLcode ftp_epsv_disable(struct connectdata *conn)
1798 {
1799   CURLcode result = CURLE_OK;
1800   infof(conn->data, "got positive EPSV response, but can't connect. "
1801         "Disabling EPSV\n");
1802   /* disable it for next transfer */
1803   conn->bits.ftp_use_epsv = FALSE;
1804   conn->data->state.errorbuf = FALSE; /* allow error message to get
1805                                          rewritten */
1806   PPSENDF(&conn->proto.ftpc.pp, "PASV", NULL);
1807   conn->proto.ftpc.count1++;
1808   /* remain in the FTP_PASV state */
1809   return result;
1810 }
1811
1812 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1813                                     int ftpcode)
1814 {
1815   struct ftp_conn *ftpc = &conn->proto.ftpc;
1816   CURLcode result;
1817   struct SessionHandle *data=conn->data;
1818   Curl_addrinfo *conninfo;
1819   struct Curl_dns_entry *addr=NULL;
1820   int rc;
1821   unsigned short connectport; /* the local port connect() should use! */
1822   unsigned short newport=0; /* remote port */
1823   bool connected;
1824
1825   /* newhost must be able to hold a full IP-style address in ASCII, which
1826      in the IPv6 case means 5*8-1 = 39 letters */
1827 #define NEWHOST_BUFSIZE 48
1828   char newhost[NEWHOST_BUFSIZE];
1829   char *str=&data->state.buffer[4];  /* start on the first letter */
1830
1831   if((ftpc->count1 == 0) &&
1832      (ftpcode == 229)) {
1833     /* positive EPSV response */
1834     char *ptr = strchr(str, '(');
1835     if(ptr) {
1836       unsigned int num;
1837       char separator[4];
1838       ptr++;
1839       if(5  == sscanf(ptr, "%c%c%c%u%c",
1840                       &separator[0],
1841                       &separator[1],
1842                       &separator[2],
1843                       &num,
1844                       &separator[3])) {
1845         const char sep1 = separator[0];
1846         int i;
1847
1848         /* The four separators should be identical, or else this is an oddly
1849            formatted reply and we bail out immediately. */
1850         for(i=1; i<4; i++) {
1851           if(separator[i] != sep1) {
1852             ptr=NULL; /* set to NULL to signal error */
1853             break;
1854           }
1855         }
1856         if(num > 0xffff) {
1857           failf(data, "Illegal port number in EPSV reply");
1858           return CURLE_FTP_WEIRD_PASV_REPLY;
1859         }
1860         if(ptr) {
1861           newport = (unsigned short)(num & 0xffff);
1862
1863           if(conn->bits.tunnel_proxy ||
1864              conn->proxytype == CURLPROXY_SOCKS5 ||
1865              conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1866              conn->proxytype == CURLPROXY_SOCKS4 ||
1867              conn->proxytype == CURLPROXY_SOCKS4A)
1868             /* proxy tunnel -> use other host info because ip_addr_str is the
1869                proxy address not the ftp host */
1870             snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1871           else
1872             /* use the same IP we are already connected to */
1873             snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
1874         }
1875       }
1876       else
1877         ptr=NULL;
1878     }
1879     if(!ptr) {
1880       failf(data, "Weirdly formatted EPSV reply");
1881       return CURLE_FTP_WEIRD_PASV_REPLY;
1882     }
1883   }
1884   else if((ftpc->count1 == 1) &&
1885           (ftpcode == 227)) {
1886     /* positive PASV response */
1887     int ip[4];
1888     int port[2];
1889
1890     /*
1891      * Scan for a sequence of six comma-separated numbers and use them as
1892      * IP+port indicators.
1893      *
1894      * Found reply-strings include:
1895      * "227 Entering Passive Mode (127,0,0,1,4,51)"
1896      * "227 Data transfer will passively listen to 127,0,0,1,4,51"
1897      * "227 Entering passive mode. 127,0,0,1,4,51"
1898      */
1899     while(*str) {
1900       if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
1901                       &ip[0], &ip[1], &ip[2], &ip[3],
1902                       &port[0], &port[1]))
1903         break;
1904       str++;
1905     }
1906
1907     if(!*str) {
1908       failf(data, "Couldn't interpret the 227-response");
1909       return CURLE_FTP_WEIRD_227_FORMAT;
1910     }
1911
1912     /* we got OK from server */
1913     if(data->set.ftp_skip_ip) {
1914       /* told to ignore the remotely given IP but instead use the one we used
1915          for the control connection */
1916       infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
1917             ip[0], ip[1], ip[2], ip[3],
1918             conn->ip_addr_str);
1919       if(conn->bits.tunnel_proxy ||
1920          conn->proxytype == CURLPROXY_SOCKS5 ||
1921          conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
1922          conn->proxytype == CURLPROXY_SOCKS4 ||
1923          conn->proxytype == CURLPROXY_SOCKS4A)
1924         /* proxy tunnel -> use other host info because ip_addr_str is the
1925            proxy address not the ftp host */
1926         snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
1927       else
1928         snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
1929     }
1930     else
1931       snprintf(newhost, sizeof(newhost),
1932                "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1933     newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1934   }
1935   else if(ftpc->count1 == 0) {
1936     /* EPSV failed, move on to PASV */
1937
1938     /* disable it for next transfer */
1939     conn->bits.ftp_use_epsv = FALSE;
1940     infof(data, "disabling EPSV usage\n");
1941
1942     PPSENDF(&ftpc->pp, "PASV", NULL);
1943     ftpc->count1++;
1944     /* remain in the FTP_PASV state */
1945     return result;
1946   }
1947   else {
1948     failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
1949     return CURLE_FTP_WEIRD_PASV_REPLY;
1950   }
1951
1952   if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) {
1953     /*
1954      * This is a tunnel through a http proxy and we need to connect to the
1955      * proxy again here.
1956      *
1957      * We don't want to rely on a former host lookup that might've expired
1958      * 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 != 220) {
2713         failf(data, "Got a %03d ftp-server response when 220 was expected",
2714               ftpcode);
2715         return CURLE_FTP_WEIRD_SERVER_REPLY;
2716       }
2717
2718       /* We have received a 220 response fine, now we proceed. */
2719 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
2720       if(data->set.krb) {
2721         /* If not anonymous login, try a secure login. Note that this
2722            procedure is still BLOCKING. */
2723
2724         Curl_sec_request_prot(conn, "private");
2725         /* We set private first as default, in case the line below fails to
2726            set a valid level */
2727         Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
2728
2729         if(Curl_sec_login(conn) != CURLE_OK)
2730           infof(data, "Logging in with password in cleartext!\n");
2731         else
2732           infof(data, "Authentication successful\n");
2733       }
2734 #endif
2735
2736       if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
2737         /* We don't have a SSL/TLS connection yet, but FTPS is
2738            requested. Try a FTPS connection now */
2739
2740         ftpc->count3=0;
2741         switch(data->set.ftpsslauth) {
2742         case CURLFTPAUTH_DEFAULT:
2743         case CURLFTPAUTH_SSL:
2744           ftpc->count2 = 1; /* add one to get next */
2745           ftpc->count1 = 0;
2746           break;
2747         case CURLFTPAUTH_TLS:
2748           ftpc->count2 = -1; /* subtract one to get next */
2749           ftpc->count1 = 1;
2750           break;
2751         default:
2752           failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
2753                 (int)data->set.ftpsslauth);
2754           return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
2755         }
2756         PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2757         state(conn, FTP_AUTH);
2758       }
2759       else {
2760         result = ftp_state_user(conn);
2761         if(result)
2762           return result;
2763       }
2764
2765       break;
2766
2767     case FTP_AUTH:
2768       /* we have gotten the response to a previous AUTH command */
2769
2770       /* RFC2228 (page 5) says:
2771        *
2772        * If the server is willing to accept the named security mechanism,
2773        * and does not require any security data, it must respond with
2774        * reply code 234/334.
2775        */
2776
2777       if((ftpcode == 234) || (ftpcode == 334)) {
2778         /* Curl_ssl_connect is BLOCKING */
2779         result = Curl_ssl_connect(conn, FIRSTSOCKET);
2780         if(CURLE_OK == result) {
2781           conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
2782           result = ftp_state_user(conn);
2783         }
2784       }
2785       else if(ftpc->count3 < 1) {
2786         ftpc->count3++;
2787         ftpc->count1 += ftpc->count2; /* get next attempt */
2788         result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
2789         /* remain in this same state */
2790       }
2791       else {
2792         if(data->set.use_ssl > CURLUSESSL_TRY)
2793           /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
2794           result = CURLE_USE_SSL_FAILED;
2795         else
2796           /* ignore the failure and continue */
2797           result = ftp_state_user(conn);
2798       }
2799
2800       if(result)
2801         return result;
2802       break;
2803
2804     case FTP_USER:
2805     case FTP_PASS:
2806       result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2807       break;
2808
2809     case FTP_ACCT:
2810       result = ftp_state_acct_resp(conn, ftpcode);
2811       break;
2812
2813     case FTP_PBSZ:
2814       PPSENDF(&ftpc->pp, "PROT %c",
2815               data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
2816       state(conn, FTP_PROT);
2817
2818       break;
2819
2820     case FTP_PROT:
2821       if(ftpcode/100 == 2)
2822         /* We have enabled SSL for the data connection! */
2823         conn->ssl[SECONDARYSOCKET].use =
2824           (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
2825       /* FTP servers typically responds with 500 if they decide to reject
2826          our 'P' request */
2827       else if(data->set.use_ssl > CURLUSESSL_CONTROL)
2828         /* we failed and bails out */
2829         return CURLE_USE_SSL_FAILED;
2830
2831       if(data->set.ftp_ccc) {
2832         /* CCC - Clear Command Channel
2833          */
2834         PPSENDF(&ftpc->pp, "CCC", NULL);
2835         state(conn, FTP_CCC);
2836       }
2837       else {
2838         result = ftp_state_pwd(conn);
2839         if(result)
2840           return result;
2841       }
2842       break;
2843
2844     case FTP_CCC:
2845       if(ftpcode < 500) {
2846         /* First shut down the SSL layer (note: this call will block) */
2847         result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
2848
2849         if(result) {
2850           failf(conn->data, "Failed to clear the command channel (CCC)");
2851           return result;
2852         }
2853       }
2854
2855       /* Then continue as normal */
2856       result = ftp_state_pwd(conn);
2857       if(result)
2858         return result;
2859       break;
2860
2861     case FTP_PWD:
2862       if(ftpcode == 257) {
2863         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2864         char *dir;
2865         char *store;
2866
2867         dir = malloc(nread + 1);
2868         if(!dir)
2869           return CURLE_OUT_OF_MEMORY;
2870
2871         /* Reply format is like
2872            257<space>"<directory-name>"<space><commentary> and the RFC959
2873            says
2874
2875            The directory name can contain any character; embedded
2876            double-quotes should be escaped by double-quotes (the
2877            "quote-doubling" convention).
2878         */
2879         if('\"' == *ptr) {
2880           /* it started good */
2881           ptr++;
2882           for(store = dir; *ptr;) {
2883             if('\"' == *ptr) {
2884               if('\"' == ptr[1]) {
2885                 /* "quote-doubling" */
2886                 *store = ptr[1];
2887                 ptr++;
2888               }
2889               else {
2890                 /* end of path */
2891                 *store = '\0'; /* zero terminate */
2892                 break; /* get out of this loop */
2893               }
2894             }
2895             else
2896               *store = *ptr;
2897             store++;
2898             ptr++;
2899           }
2900
2901           /* If the path name does not look like an absolute path (i.e.: it
2902              does not start with a '/'), we probably need some server-dependent
2903              adjustments. For example, this is the case when connecting to
2904              an OS400 FTP server: this server supports two name syntaxes,
2905              the default one being incompatible with standard pathes. In
2906              addition, this server switches automatically to the regular path
2907              syntax when one is encountered in a command: this results in
2908              having an entrypath in the wrong syntax when later used in CWD.
2909                The method used here is to check the server OS: we do it only
2910              if the path name looks strange to minimize overhead on other
2911              systems. */
2912
2913           if(!ftpc->server_os && dir[0] != '/') {
2914
2915             result = Curl_pp_sendf(&ftpc->pp, "SYST", NULL);
2916             if(result != CURLE_OK) {
2917               free(dir);
2918               return result;
2919             }
2920             Curl_safefree(ftpc->entrypath);
2921             ftpc->entrypath = dir; /* remember this */
2922             infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2923             /* also save it where getinfo can access it: */
2924             data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2925             state(conn, FTP_SYST);
2926             break;
2927           }
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         }
2935         else {
2936           /* couldn't get the path */
2937           free(dir);
2938           infof(data, "Failed to figure out path\n");
2939         }
2940       }
2941       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2942       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2943       break;
2944
2945     case FTP_SYST:
2946       if(ftpcode == 215) {
2947         char *ptr=&data->state.buffer[4];  /* start on the first letter */
2948         char *os;
2949         char *store;
2950
2951         os = malloc(nread + 1);
2952         if(!os)
2953           return CURLE_OUT_OF_MEMORY;
2954
2955         /* Reply format is like
2956            215<space><OS-name><space><commentary>
2957         */
2958         while(*ptr == ' ')
2959           ptr++;
2960         for(store = os; *ptr && *ptr != ' ';)
2961           *store++ = *ptr++;
2962         *store = '\0'; /* zero terminate */
2963
2964         /* Check for special servers here. */
2965
2966         if(strequal(os, "OS/400")) {
2967           /* Force OS400 name format 1. */
2968           result = Curl_pp_sendf(&ftpc->pp, "SITE NAMEFMT 1", NULL);
2969           if(result != CURLE_OK) {
2970             free(os);
2971             return result;
2972           }
2973           /* remember target server OS */
2974           Curl_safefree(ftpc->server_os);
2975           ftpc->server_os = os;
2976           state(conn, FTP_NAMEFMT);
2977           break;
2978         }
2979         else {
2980           /* Nothing special for the target server. */
2981           /* remember target server OS */
2982           Curl_safefree(ftpc->server_os);
2983           ftpc->server_os = os;
2984         }
2985       }
2986       else {
2987         /* Cannot identify server OS. Continue anyway and cross fingers. */
2988       }
2989
2990       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
2991       DEBUGF(infof(data, "protocol connect phase DONE\n"));
2992       break;
2993
2994     case FTP_NAMEFMT:
2995       if(ftpcode == 250) {
2996         /* Name format change successful: reload initial path. */
2997         ftp_state_pwd(conn);
2998         break;
2999       }
3000
3001       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
3002       DEBUGF(infof(data, "protocol connect phase DONE\n"));
3003       break;
3004
3005     case FTP_QUOTE:
3006     case FTP_POSTQUOTE:
3007     case FTP_RETR_PREQUOTE:
3008     case FTP_STOR_PREQUOTE:
3009       if((ftpcode >= 400) && !ftpc->count2) {
3010         /* failure response code, and not allowed to fail */
3011         failf(conn->data, "QUOT command failed with %03d", ftpcode);
3012         return CURLE_QUOTE_ERROR;
3013       }
3014       result = ftp_state_quote(conn, FALSE, ftpc->state);
3015       if(result)
3016         return result;
3017
3018       break;
3019
3020     case FTP_CWD:
3021       if(ftpcode/100 != 2) {
3022         /* failure to CWD there */
3023         if(conn->data->set.ftp_create_missing_dirs &&
3024            ftpc->count1 && !ftpc->count2) {
3025           /* try making it */
3026           ftpc->count2++; /* counter to prevent CWD-MKD loops */
3027           PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
3028           state(conn, FTP_MKD);
3029         }
3030         else {
3031           /* return failure */
3032           failf(data, "Server denied you to change to the given directory");
3033           ftpc->cwdfail = TRUE; /* don't remember this path as we failed
3034                                    to enter it */
3035           return CURLE_REMOTE_ACCESS_DENIED;
3036         }
3037       }
3038       else {
3039         /* success */
3040         ftpc->count2=0;
3041         if(++ftpc->count1 <= ftpc->dirdepth) {
3042           /* send next CWD */
3043           PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3044         }
3045         else {
3046           result = ftp_state_post_cwd(conn);
3047           if(result)
3048             return result;
3049         }
3050       }
3051       break;
3052
3053     case FTP_MKD:
3054       if((ftpcode/100 != 2) && !ftpc->count3--) {
3055         /* failure to MKD the dir */
3056         failf(data, "Failed to MKD dir: %03d", ftpcode);
3057         return CURLE_REMOTE_ACCESS_DENIED;
3058       }
3059       state(conn, FTP_CWD);
3060       /* send CWD */
3061       PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
3062       break;
3063
3064     case FTP_MDTM:
3065       result = ftp_state_mdtm_resp(conn, ftpcode);
3066       break;
3067
3068     case FTP_TYPE:
3069     case FTP_LIST_TYPE:
3070     case FTP_RETR_TYPE:
3071     case FTP_STOR_TYPE:
3072       result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
3073       break;
3074
3075     case FTP_SIZE:
3076     case FTP_RETR_SIZE:
3077     case FTP_STOR_SIZE:
3078       result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
3079       break;
3080
3081     case FTP_REST:
3082     case FTP_RETR_REST:
3083       result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
3084       break;
3085
3086     case FTP_PRET:
3087       if(ftpcode != 200) {
3088         /* there only is this one standard OK return code. */
3089         failf(data, "PRET command not accepted: %03d", ftpcode);
3090         return CURLE_FTP_PRET_FAILED;
3091       }
3092       result = ftp_state_use_pasv(conn);
3093       break;
3094
3095     case FTP_PASV:
3096       result = ftp_state_pasv_resp(conn, ftpcode);
3097       break;
3098
3099     case FTP_PORT:
3100       result = ftp_state_port_resp(conn, ftpcode);
3101       break;
3102
3103     case FTP_LIST:
3104     case FTP_RETR:
3105       result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
3106       break;
3107
3108     case FTP_STOR:
3109       result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
3110       break;
3111
3112     case FTP_QUIT:
3113       /* fallthrough, just stop! */
3114     default:
3115       /* internal error */
3116       state(conn, FTP_STOP);
3117       break;
3118     }
3119   } /* if(ftpcode) */
3120
3121   return result;
3122 }
3123
3124
3125 /* called repeatedly until done from multi.c */
3126 static CURLcode ftp_multi_statemach(struct connectdata *conn,
3127                                     bool *done)
3128 {
3129   struct ftp_conn *ftpc = &conn->proto.ftpc;
3130   CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
3131
3132   /* Check for the state outside of the Curl_socket_ready() return code checks
3133      since at times we are in fact already in this state when this function
3134      gets called. */
3135   *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
3136
3137   return result;
3138 }
3139
3140 static CURLcode ftp_block_statemach(struct connectdata *conn)
3141 {
3142   struct ftp_conn *ftpc = &conn->proto.ftpc;
3143   struct pingpong *pp = &ftpc->pp;
3144   CURLcode result = CURLE_OK;
3145
3146   while(ftpc->state != FTP_STOP) {
3147     result = Curl_pp_statemach(pp, TRUE);
3148     if(result)
3149       break;
3150   }
3151
3152   return result;
3153 }
3154
3155 /*
3156  * Allocate and initialize the struct FTP for the current SessionHandle.  If
3157  * need be.
3158  */
3159
3160 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
3161     defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
3162   /* workaround icc 9.1 optimizer issue */
3163 #pragma optimize("", off)
3164 #endif
3165
3166 static CURLcode ftp_init(struct connectdata *conn)
3167 {
3168   struct FTP *ftp;
3169
3170   if(NULL == conn->data->state.proto.ftp) {
3171     conn->data->state.proto.ftp = malloc(sizeof(struct FTP));
3172     if(NULL == conn->data->state.proto.ftp)
3173       return CURLE_OUT_OF_MEMORY;
3174   }
3175
3176   ftp = conn->data->state.proto.ftp;
3177
3178   /* get some initial data into the ftp struct */
3179   ftp->bytecountp = &conn->data->req.bytecount;
3180   ftp->transfer = FTPTRANSFER_BODY;
3181   ftp->downloadsize = 0;
3182
3183   /* No need to duplicate user+password, the connectdata struct won't change
3184      during a session, but we re-init them here since on subsequent inits
3185      since the conn struct may have changed or been replaced.
3186   */
3187   ftp->user = conn->user;
3188   ftp->passwd = conn->passwd;
3189   if(isBadFtpString(ftp->user))
3190     return CURLE_URL_MALFORMAT;
3191   if(isBadFtpString(ftp->passwd))
3192     return CURLE_URL_MALFORMAT;
3193
3194   conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
3195
3196   return CURLE_OK;
3197 }
3198
3199 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
3200     defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
3201   /* workaround icc 9.1 optimizer issue */
3202 #pragma optimize("", on)
3203 #endif
3204
3205 /*
3206  * ftp_connect() should do everything that is to be considered a part of
3207  * the connection phase.
3208  *
3209  * The variable 'done' points to will be TRUE if the protocol-layer connect
3210  * phase is done when this function returns, or FALSE is not. When called as
3211  * a part of the easy interface, it will always be TRUE.
3212  */
3213 static CURLcode ftp_connect(struct connectdata *conn,
3214                                  bool *done) /* see description above */
3215 {
3216   CURLcode result;
3217   struct ftp_conn *ftpc = &conn->proto.ftpc;
3218   struct pingpong *pp = &ftpc->pp;
3219
3220   *done = FALSE; /* default to not done yet */
3221
3222   /* If there already is a protocol-specific struct allocated for this
3223      sessionhandle, deal with it */
3224   Curl_reset_reqproto(conn);
3225
3226   result = ftp_init(conn);
3227   if(CURLE_OK != result)
3228     return result;
3229
3230   /* We always support persistent connections on ftp */
3231   conn->bits.close = FALSE;
3232
3233   pp->response_time = RESP_TIMEOUT; /* set default response time-out */
3234   pp->statemach_act = ftp_statemach_act;
3235   pp->endofresp = ftp_endofresp;
3236   pp->conn = conn;
3237
3238   if(conn->handler->flags & PROTOPT_SSL) {
3239     /* BLOCKING */
3240     result = Curl_ssl_connect(conn, FIRSTSOCKET);
3241     if(result)
3242       return result;
3243   }
3244
3245   Curl_pp_init(pp); /* init the generic pingpong data */
3246
3247   /* When we connect, we start in the state where we await the 220
3248      response */
3249   state(conn, FTP_WAIT220);
3250
3251   result = ftp_multi_statemach(conn, done);
3252
3253   return result;
3254 }
3255
3256 /***********************************************************************
3257  *
3258  * ftp_done()
3259  *
3260  * The DONE function. This does what needs to be done after a single DO has
3261  * performed.
3262  *
3263  * Input argument is already checked for validity.
3264  */
3265 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
3266                               bool premature)
3267 {
3268   struct SessionHandle *data = conn->data;
3269   struct FTP *ftp = data->state.proto.ftp;
3270   struct ftp_conn *ftpc = &conn->proto.ftpc;
3271   struct pingpong *pp = &ftpc->pp;
3272   ssize_t nread;
3273   int ftpcode;
3274   CURLcode result = CURLE_OK;
3275   bool was_ctl_valid = ftpc->ctl_valid;
3276   char *path;
3277   const char *path_to_use = data->state.path;
3278
3279   if(!ftp)
3280     /* When the easy handle is removed from the multi while libcurl is still
3281      * trying to resolve the host name, it seems that the ftp struct is not
3282      * yet initialized, but the removal action calls Curl_done() which calls
3283      * this function. So we simply return success if no ftp pointer is set.
3284      */
3285     return CURLE_OK;
3286
3287   switch(status) {
3288   case CURLE_BAD_DOWNLOAD_RESUME:
3289   case CURLE_FTP_WEIRD_PASV_REPLY:
3290   case CURLE_FTP_PORT_FAILED:
3291   case CURLE_FTP_ACCEPT_FAILED:
3292   case CURLE_FTP_ACCEPT_TIMEOUT:
3293   case CURLE_FTP_COULDNT_SET_TYPE:
3294   case CURLE_FTP_COULDNT_RETR_FILE:
3295   case CURLE_PARTIAL_FILE:
3296   case CURLE_UPLOAD_FAILED:
3297   case CURLE_REMOTE_ACCESS_DENIED:
3298   case CURLE_FILESIZE_EXCEEDED:
3299   case CURLE_REMOTE_FILE_NOT_FOUND:
3300   case CURLE_WRITE_ERROR:
3301     /* the connection stays alive fine even though this happened */
3302     /* fall-through */
3303   case CURLE_OK: /* doesn't affect the control connection's status */
3304     if(!premature) {
3305       ftpc->ctl_valid = was_ctl_valid;
3306       break;
3307     }
3308     /* until we cope better with prematurely ended requests, let them
3309      * fallback as if in complete failure */
3310   default:       /* by default, an error means the control connection is
3311                     wedged and should not be used anymore */
3312     ftpc->ctl_valid = FALSE;
3313     ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
3314                              current path, as this connection is going */
3315     conn->bits.close = TRUE; /* marked for closure */
3316     result = status;      /* use the already set error code */
3317     break;
3318   }
3319
3320   /* now store a copy of the directory we are in */
3321   if(ftpc->prevpath)
3322     free(ftpc->prevpath);
3323
3324   if(data->set.wildcardmatch) {
3325     if(data->set.chunk_end && ftpc->file) {
3326       data->set.chunk_end(data->wildcard.customptr);
3327     }
3328     ftpc->known_filesize = -1;
3329   }
3330
3331   /* get the "raw" path */
3332   path = curl_easy_unescape(data, path_to_use, 0, NULL);
3333   if(!path) {
3334     /* out of memory, but we can limp along anyway (and should try to
3335      * since we may already be in the out of memory cleanup path) */
3336     if(!result)
3337       result = CURLE_OUT_OF_MEMORY;
3338     ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3339     conn->bits.close = TRUE; /* mark for connection closure */
3340     ftpc->prevpath = NULL; /* no path remembering */
3341   }
3342   else {
3343     size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
3344     size_t dlen = strlen(path)-flen;
3345     if(!ftpc->cwdfail) {
3346       if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
3347         ftpc->prevpath = path;
3348         if(flen)
3349           /* if 'path' is not the whole string */
3350           ftpc->prevpath[dlen]=0; /* terminate */
3351       }
3352       else {
3353         /* we never changed dir */
3354         ftpc->prevpath=strdup("");
3355         free(path);
3356       }
3357       if(ftpc->prevpath)
3358         infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
3359     }
3360     else {
3361       ftpc->prevpath = NULL; /* no path */
3362       free(path);
3363     }
3364   }
3365   /* free the dir tree and file parts */
3366   freedirs(ftpc);
3367
3368   /* shut down the socket to inform the server we're done */
3369
3370 #ifdef _WIN32_WCE
3371   shutdown(conn->sock[SECONDARYSOCKET],2);  /* SD_BOTH */
3372 #endif
3373
3374   if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
3375     if(!result && ftpc->dont_check && data->req.maxdownload > 0)
3376       /* partial download completed */
3377       result = Curl_pp_sendf(pp, "ABOR");
3378       if(result) {
3379         failf(data, "Failure sending ABOR command: %s",
3380               curl_easy_strerror(result));
3381         ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3382         conn->bits.close = TRUE; /* mark for connection closure */
3383       }
3384
3385     if(conn->ssl[SECONDARYSOCKET].use) {
3386       /* The secondary socket is using SSL so we must close down that part
3387          first before we close the socket for real */
3388       Curl_ssl_close(conn, SECONDARYSOCKET);
3389
3390       /* Note that we keep "use" set to TRUE since that (next) connection is
3391          still requested to use SSL */
3392     }
3393     if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
3394       Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
3395       conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
3396       conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
3397     }
3398   }
3399
3400   if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
3401      pp->pending_resp && !premature) {
3402     /*
3403      * Let's see what the server says about the transfer we just performed,
3404      * but lower the timeout as sometimes this connection has died while the
3405      * data has been transferred. This happens when doing through NATs etc that
3406      * abandon old silent connections.
3407      */
3408     long old_time = pp->response_time;
3409
3410     pp->response_time = 60*1000; /* give it only a minute for now */
3411     pp->response = Curl_tvnow(); /* timeout relative now */
3412
3413     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3414
3415     pp->response_time = old_time; /* set this back to previous value */
3416
3417     if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
3418       failf(data, "control connection looks dead");
3419       ftpc->ctl_valid = FALSE; /* mark control connection as bad */
3420       conn->bits.close = TRUE; /* mark for closure */
3421     }
3422
3423     if(result)
3424       return result;
3425
3426     if(ftpc->dont_check && data->req.maxdownload > 0) {
3427       /* we have just sent ABOR and there is no reliable way to check if it was
3428        * successful or not; we have to close the connection now */
3429       infof(data, "partial download completed, closing connection\n");
3430       conn->bits.close = TRUE; /* mark for closure */
3431       return result;
3432     }
3433
3434     if(!ftpc->dont_check) {
3435       /* 226 Transfer complete, 250 Requested file action okay, completed. */
3436       if((ftpcode != 226) && (ftpcode != 250)) {
3437         failf(data, "server did not report OK, got %d", ftpcode);
3438         result = CURLE_PARTIAL_FILE;
3439       }
3440     }
3441   }
3442
3443   if(result || premature)
3444     /* the response code from the transfer showed an error already so no
3445        use checking further */
3446     ;
3447   else if(data->set.upload) {
3448     if((-1 != data->set.infilesize) &&
3449        (data->set.infilesize != *ftp->bytecountp) &&
3450        !data->set.crlf &&
3451        (ftp->transfer == FTPTRANSFER_BODY)) {
3452       failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
3453             " out of %" FORMAT_OFF_T " bytes)",
3454             *ftp->bytecountp, data->set.infilesize);
3455       result = CURLE_PARTIAL_FILE;
3456     }
3457   }
3458   else {
3459     if((-1 != data->req.size) &&
3460        (data->req.size != *ftp->bytecountp) &&
3461 #ifdef CURL_DO_LINEEND_CONV
3462        /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3463         * we'll check to see if the discrepancy can be explained by the number
3464         * of CRLFs we've changed to LFs.
3465         */
3466        ((data->req.size + data->state.crlf_conversions) !=
3467         *ftp->bytecountp) &&
3468 #endif /* CURL_DO_LINEEND_CONV */
3469        (data->req.maxdownload != *ftp->bytecountp)) {
3470       failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
3471             *ftp->bytecountp);
3472       result = CURLE_PARTIAL_FILE;
3473     }
3474     else if(!ftpc->dont_check &&
3475             !*ftp->bytecountp &&
3476             (data->req.size>0)) {
3477       failf(data, "No data was received!");
3478       result = CURLE_FTP_COULDNT_RETR_FILE;
3479     }
3480   }
3481
3482   /* clear these for next connection */
3483   ftp->transfer = FTPTRANSFER_BODY;
3484   ftpc->dont_check = FALSE;
3485
3486   /* Send any post-transfer QUOTE strings? */
3487   if(!status && !result && !premature && data->set.postquote)
3488     result = ftp_sendquote(conn, data->set.postquote);
3489
3490   return result;
3491 }
3492
3493 /***********************************************************************
3494  *
3495  * ftp_sendquote()
3496  *
3497  * Where a 'quote' means a list of custom commands to send to the server.
3498  * The quote list is passed as an argument.
3499  *
3500  * BLOCKING
3501  */
3502
3503 static
3504 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
3505 {
3506   struct curl_slist *item;
3507   ssize_t nread;
3508   int ftpcode;
3509   CURLcode result;
3510   struct ftp_conn *ftpc = &conn->proto.ftpc;
3511   struct pingpong *pp = &ftpc->pp;
3512
3513   item = quote;
3514   while(item) {
3515     if(item->data) {
3516       char *cmd = item->data;
3517       bool acceptfail = FALSE;
3518
3519       /* if a command starts with an asterisk, which a legal FTP command never
3520          can, the command will be allowed to fail without it causing any
3521          aborts or cancels etc. It will cause libcurl to act as if the command
3522          is successful, whatever the server reponds. */
3523
3524       if(cmd[0] == '*') {
3525         cmd++;
3526         acceptfail = TRUE;
3527       }
3528
3529       PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
3530
3531       pp->response = Curl_tvnow(); /* timeout relative now */
3532
3533       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3534       if(result)
3535         return result;
3536
3537       if(!acceptfail && (ftpcode >= 400)) {
3538         failf(conn->data, "QUOT string not accepted: %s", cmd);
3539         return CURLE_QUOTE_ERROR;
3540       }
3541     }
3542
3543     item = item->next;
3544   }
3545
3546   return CURLE_OK;
3547 }
3548
3549 /***********************************************************************
3550  *
3551  * ftp_need_type()
3552  *
3553  * Returns TRUE if we in the current situation should send TYPE
3554  */
3555 static int ftp_need_type(struct connectdata *conn,
3556                          bool ascii_wanted)
3557 {
3558   return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
3559 }
3560
3561 /***********************************************************************
3562  *
3563  * ftp_nb_type()
3564  *
3565  * Set TYPE. We only deal with ASCII or BINARY so this function
3566  * sets one of them.
3567  * If the transfer type is not sent, simulate on OK response in newstate
3568  */
3569 static CURLcode ftp_nb_type(struct connectdata *conn,
3570                             bool ascii, ftpstate newstate)
3571 {
3572   struct ftp_conn *ftpc = &conn->proto.ftpc;
3573   CURLcode result;
3574   char want = (char)(ascii?'A':'I');
3575
3576   if(ftpc->transfertype == want) {
3577     state(conn, newstate);
3578     return ftp_state_type_resp(conn, 200, newstate);
3579   }
3580
3581   PPSENDF(&ftpc->pp, "TYPE %c", want);
3582   state(conn, newstate);
3583
3584   /* keep track of our current transfer type */
3585   ftpc->transfertype = want;
3586   return CURLE_OK;
3587 }
3588
3589 /***************************************************************************
3590  *
3591  * ftp_pasv_verbose()
3592  *
3593  * This function only outputs some informationals about this second connection
3594  * when we've issued a PASV command before and thus we have connected to a
3595  * possibly new IP address.
3596  *
3597  */
3598 #ifndef CURL_DISABLE_VERBOSE_STRINGS
3599 static void
3600 ftp_pasv_verbose(struct connectdata *conn,
3601                  Curl_addrinfo *ai,
3602                  char *newhost, /* ascii version */
3603                  int port)
3604 {
3605   char buf[256];
3606   Curl_printable_address(ai, buf, sizeof(buf));
3607   infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3608 }
3609 #endif
3610
3611 /*
3612   Check if this is a range download, and if so, set the internal variables
3613   properly.
3614  */
3615
3616 static CURLcode ftp_range(struct connectdata *conn)
3617 {
3618   curl_off_t from, to;
3619   char *ptr;
3620   char *ptr2;
3621   struct SessionHandle *data = conn->data;
3622   struct ftp_conn *ftpc = &conn->proto.ftpc;
3623
3624   if(data->state.use_range && data->state.range) {
3625     from=curlx_strtoofft(data->state.range, &ptr, 0);
3626     while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3627       ptr++;
3628     to=curlx_strtoofft(ptr, &ptr2, 0);
3629     if(ptr == ptr2) {
3630       /* we didn't get any digit */
3631       to=-1;
3632     }
3633     if((-1 == to) && (from>=0)) {
3634       /* X - */
3635       data->state.resume_from = from;
3636       DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
3637                    from));
3638     }
3639     else if(from < 0) {
3640       /* -Y */
3641       data->req.maxdownload = -from;
3642       data->state.resume_from = from;
3643       DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
3644                    -from));
3645     }
3646     else {
3647       /* X-Y */
3648       data->req.maxdownload = (to-from)+1; /* include last byte */
3649       data->state.resume_from = from;
3650       DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
3651                    " getting %" FORMAT_OFF_T " bytes\n",
3652                    from, data->req.maxdownload));
3653     }
3654     DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
3655                  " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
3656                  from, to, data->req.maxdownload));
3657     ftpc->dont_check = TRUE; /* dont check for successful transfer */
3658   }
3659   else
3660     data->req.maxdownload = -1;
3661   return CURLE_OK;
3662 }
3663
3664
3665 /*
3666  * ftp_do_more()
3667  *
3668  * This function shall be called when the second FTP (data) connection is
3669  * connected.
3670  */
3671
3672 static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
3673 {
3674   struct SessionHandle *data=conn->data;
3675   struct ftp_conn *ftpc = &conn->proto.ftpc;
3676   CURLcode result = CURLE_OK;
3677   bool connected = FALSE;
3678
3679   /* the ftp struct is inited in ftp_connect() */
3680   struct FTP *ftp = data->state.proto.ftp;
3681
3682   *complete = FALSE;
3683
3684   /* if the second connection isn't done yet, wait for it */
3685   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
3686     if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
3687       /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
3688          aren't used so we blank their arguments. TODO: make this nicer */
3689       result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
3690
3691       return result;
3692     }
3693
3694     result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3695
3696     /* Ready to do more? */
3697     if(connected) {
3698       DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
3699     }
3700     else
3701       return result;
3702   }
3703
3704   if(ftpc->state) {
3705     /* already in a state so skip the intial commands.
3706        They are only done to kickstart the do_more state */
3707     result = ftp_multi_statemach(conn, complete);
3708
3709     /* if we got an error or if we don't wait for a data connection return
3710        immediately */
3711     if(result || (ftpc->wait_data_conn != TRUE))
3712       return result;
3713
3714     if(ftpc->wait_data_conn)
3715       /* if we reach the end of the FTP state machine here, *complete will be
3716          TRUE but so is ftpc->wait_data_conn, which says we need to wait for
3717          the data connection and therefore we're not actually complete */
3718       *complete = FALSE;
3719   }
3720
3721   if(ftp->transfer <= FTPTRANSFER_INFO) {
3722     /* a transfer is about to take place, or if not a file name was given
3723        so we'll do a SIZE on it later and then we need the right TYPE first */
3724
3725     if(ftpc->wait_data_conn == TRUE) {
3726       bool serv_conned;
3727
3728       result = ReceivedServerConnect(conn, &serv_conned);
3729       if(result)
3730         return result; /* Failed to accept data connection */
3731
3732       if(serv_conned) {
3733         /* It looks data connection is established */
3734         result = AcceptServerConnect(conn);
3735         ftpc->wait_data_conn = FALSE;
3736         if(!result)
3737           result = InitiateTransfer(conn);
3738
3739         if(result)
3740           return result;
3741       }
3742     }
3743     else if(data->set.upload) {
3744       result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3745       if(result)
3746         return result;
3747
3748       result = ftp_multi_statemach(conn, complete);
3749     }
3750     else {
3751       /* download */
3752       ftp->downloadsize = -1; /* unknown as of yet */
3753
3754       result = ftp_range(conn);
3755       if(result)
3756         ;
3757       else if(data->set.ftp_list_only || !ftpc->file) {
3758         /* The specified path ends with a slash, and therefore we think this
3759            is a directory that is requested, use LIST. But before that we
3760            need to set ASCII transfer mode. */
3761
3762         /* But only if a body transfer was requested. */
3763         if(ftp->transfer == FTPTRANSFER_BODY) {
3764           result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
3765           if(result)
3766             return result;
3767         }
3768         /* otherwise just fall through */
3769       }
3770       else {
3771         result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
3772         if(result)
3773           return result;
3774       }
3775
3776       result = ftp_multi_statemach(conn, complete);
3777     }
3778     return result;
3779   }
3780
3781   if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
3782     /* no data to transfer. FIX: it feels like a kludge to have this here
3783        too! */
3784     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3785
3786   if(!ftpc->wait_data_conn) {
3787     /* no waiting for the data connection so this is now complete */
3788     *complete = TRUE;
3789     DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
3790   }
3791
3792   return result;
3793 }
3794
3795
3796
3797 /***********************************************************************
3798  *
3799  * ftp_perform()
3800  *
3801  * This is the actual DO function for FTP. Get a file/directory according to
3802  * the options previously setup.
3803  */
3804
3805 static
3806 CURLcode ftp_perform(struct connectdata *conn,
3807                      bool *connected,  /* connect status after PASV / PORT */
3808                      bool *dophase_done)
3809 {
3810   /* this is FTP and no proxy */
3811   CURLcode result=CURLE_OK;
3812
3813   DEBUGF(infof(conn->data, "DO phase starts\n"));
3814
3815   if(conn->data->set.opt_no_body) {
3816     /* requested no body means no transfer... */
3817     struct FTP *ftp = conn->data->state.proto.ftp;
3818     ftp->transfer = FTPTRANSFER_INFO;
3819   }
3820
3821   *dophase_done = FALSE; /* not done yet */
3822
3823   /* start the first command in the DO phase */
3824   result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
3825   if(result)
3826     return result;
3827
3828   /* run the state-machine */
3829   result = ftp_multi_statemach(conn, dophase_done);
3830
3831   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
3832
3833   if(*dophase_done)
3834     DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3835
3836   return result;
3837 }
3838
3839 static void wc_data_dtor(void *ptr)
3840 {
3841   struct ftp_wc_tmpdata *tmp = ptr;
3842   if(tmp)
3843     Curl_ftp_parselist_data_free(&tmp->parser);
3844   Curl_safefree(tmp);
3845 }
3846
3847 static CURLcode init_wc_data(struct connectdata *conn)
3848 {
3849   char *last_slash;
3850   char *path = conn->data->state.path;
3851   struct WildcardData *wildcard = &(conn->data->wildcard);
3852   CURLcode ret = CURLE_OK;
3853   struct ftp_wc_tmpdata *ftp_tmp;
3854
3855   last_slash = strrchr(conn->data->state.path, '/');
3856   if(last_slash) {
3857     last_slash++;
3858     if(last_slash[0] == '\0') {
3859       wildcard->state = CURLWC_CLEAN;
3860       ret = ftp_parse_url_path(conn);
3861       return ret;
3862     }
3863     else {
3864       wildcard->pattern = strdup(last_slash);
3865       if(!wildcard->pattern)
3866         return CURLE_OUT_OF_MEMORY;
3867       last_slash[0] = '\0'; /* cut file from path */
3868     }
3869   }
3870   else { /* there is only 'wildcard pattern' or nothing */
3871     if(path[0]) {
3872       wildcard->pattern = strdup(path);
3873       if(!wildcard->pattern)
3874         return CURLE_OUT_OF_MEMORY;
3875       path[0] = '\0';
3876     }
3877     else { /* only list */
3878       wildcard->state = CURLWC_CLEAN;
3879       ret = ftp_parse_url_path(conn);
3880       return ret;
3881     }
3882   }
3883
3884   /* program continues only if URL is not ending with slash, allocate needed
3885      resources for wildcard transfer */
3886
3887   /* allocate ftp protocol specific temporary wildcard data */
3888   ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
3889   if(!ftp_tmp) {
3890     Curl_safefree(wildcard->pattern);
3891     return CURLE_OUT_OF_MEMORY;
3892   }
3893
3894   /* INITIALIZE parselist structure */
3895   ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
3896   if(!ftp_tmp->parser) {
3897     Curl_safefree(wildcard->pattern);
3898     Curl_safefree(ftp_tmp);
3899     return CURLE_OUT_OF_MEMORY;
3900   }
3901
3902   wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
3903   wildcard->tmp_dtor = wc_data_dtor;
3904
3905   /* wildcard does not support NOCWD option (assert it?) */
3906   if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
3907     conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
3908
3909   /* try to parse ftp url */
3910   ret = ftp_parse_url_path(conn);
3911   if(ret) {
3912     Curl_safefree(wildcard->pattern);
3913     wildcard->tmp_dtor(wildcard->tmp);
3914     wildcard->tmp_dtor = ZERO_NULL;
3915     wildcard->tmp = NULL;
3916     return ret;
3917   }
3918
3919   wildcard->path = strdup(conn->data->state.path);
3920   if(!wildcard->path) {
3921     Curl_safefree(wildcard->pattern);
3922     wildcard->tmp_dtor(wildcard->tmp);
3923     wildcard->tmp_dtor = ZERO_NULL;
3924     wildcard->tmp = NULL;
3925     return CURLE_OUT_OF_MEMORY;
3926   }
3927
3928   /* backup old write_function */
3929   ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
3930   /* parsing write function */
3931   conn->data->set.fwrite_func = Curl_ftp_parselist;
3932   /* backup old file descriptor */
3933   ftp_tmp->backup.file_descriptor = conn->data->set.out;
3934   /* let the writefunc callback know what curl pointer is working with */
3935   conn->data->set.out = conn;
3936
3937   infof(conn->data, "Wildcard - Parsing started\n");
3938   return CURLE_OK;
3939 }
3940
3941 /* This is called recursively */
3942 static CURLcode wc_statemach(struct connectdata *conn)
3943 {
3944   struct WildcardData * const wildcard = &(conn->data->wildcard);
3945   CURLcode ret = CURLE_OK;
3946
3947   switch (wildcard->state) {
3948   case CURLWC_INIT:
3949     ret = init_wc_data(conn);
3950     if(wildcard->state == CURLWC_CLEAN)
3951       /* only listing! */
3952       break;
3953     else
3954       wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING;
3955     break;
3956
3957   case CURLWC_MATCHING: {
3958     /* In this state is LIST response successfully parsed, so lets restore
3959        previous WRITEFUNCTION callback and WRITEDATA pointer */
3960     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
3961     conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
3962     conn->data->set.out = ftp_tmp->backup.file_descriptor;
3963     ftp_tmp->backup.write_function = ZERO_NULL;
3964     ftp_tmp->backup.file_descriptor = NULL;
3965     wildcard->state = CURLWC_DOWNLOADING;
3966
3967     if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
3968       /* error found in LIST parsing */
3969       wildcard->state = CURLWC_CLEAN;
3970       return wc_statemach(conn);
3971     }
3972     else if(wildcard->filelist->size == 0) {
3973       /* no corresponding file */
3974       wildcard->state = CURLWC_CLEAN;
3975       return CURLE_REMOTE_FILE_NOT_FOUND;
3976     }
3977     return wc_statemach(conn);
3978   }
3979
3980   case CURLWC_DOWNLOADING: {
3981     /* filelist has at least one file, lets get first one */
3982     struct ftp_conn *ftpc = &conn->proto.ftpc;
3983     struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
3984
3985     char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
3986     if(!tmp_path)
3987       return CURLE_OUT_OF_MEMORY;
3988
3989     /* switch default "state.pathbuffer" and tmp_path, good to see
3990        ftp_parse_url_path function to understand this trick */
3991     Curl_safefree(conn->data->state.pathbuffer);
3992     conn->data->state.pathbuffer = tmp_path;
3993     conn->data->state.path = tmp_path;
3994
3995     infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
3996     if(conn->data->set.chunk_bgn) {
3997       long userresponse = conn->data->set.chunk_bgn(
3998           finfo, wildcard->customptr, (int)wildcard->filelist->size);
3999       switch(userresponse) {
4000       case CURL_CHUNK_BGN_FUNC_SKIP:
4001         infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
4002               finfo->filename);
4003         wildcard->state = CURLWC_SKIP;
4004         return wc_statemach(conn);
4005       case CURL_CHUNK_BGN_FUNC_FAIL:
4006         return CURLE_CHUNK_FAILED;
4007       }
4008     }
4009
4010     if(finfo->filetype != CURLFILETYPE_FILE) {
4011       wildcard->state = CURLWC_SKIP;
4012       return wc_statemach(conn);
4013     }
4014
4015     if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
4016       ftpc->known_filesize = finfo->size;
4017
4018     ret = ftp_parse_url_path(conn);
4019     if(ret) {
4020       return ret;
4021     }
4022
4023     /* we don't need the Curl_fileinfo of first file anymore */
4024     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4025
4026     if(wildcard->filelist->size == 0) { /* remains only one file to down. */
4027       wildcard->state = CURLWC_CLEAN;
4028       /* after that will be ftp_do called once again and no transfer
4029          will be done because of CURLWC_CLEAN state */
4030       return CURLE_OK;
4031     }
4032   } break;
4033
4034   case CURLWC_SKIP: {
4035     if(conn->data->set.chunk_end)
4036       conn->data->set.chunk_end(conn->data->wildcard.customptr);
4037     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
4038     wildcard->state = (wildcard->filelist->size == 0) ?
4039                       CURLWC_CLEAN : CURLWC_DOWNLOADING;
4040     return wc_statemach(conn);
4041   }
4042
4043   case CURLWC_CLEAN: {
4044     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
4045     ret = CURLE_OK;
4046     if(ftp_tmp) {
4047       ret = Curl_ftp_parselist_geterror(ftp_tmp->parser);
4048     }
4049     wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE;
4050   } break;
4051
4052   case CURLWC_DONE:
4053   case CURLWC_ERROR:
4054     break;
4055   }
4056
4057   return ret;
4058 }
4059
4060 /***********************************************************************
4061  *
4062  * ftp_do()
4063  *
4064  * This function is registered as 'curl_do' function. It decodes the path
4065  * parts etc as a wrapper to the actual DO function (ftp_perform).
4066  *
4067  * The input argument is already checked for validity.
4068  */
4069 static CURLcode ftp_do(struct connectdata *conn, bool *done)
4070 {
4071   CURLcode retcode = CURLE_OK;
4072   struct ftp_conn *ftpc = &conn->proto.ftpc;
4073
4074   *done = FALSE; /* default to false */
4075   ftpc->wait_data_conn = FALSE; /* default to no such wait */
4076
4077   /*
4078     Since connections can be re-used between SessionHandles, this might be a
4079     connection already existing but on a fresh SessionHandle struct so we must
4080     make sure we have a good 'struct FTP' to play with. For new connections,
4081     the struct FTP is allocated and setup in the ftp_connect() function.
4082   */
4083   Curl_reset_reqproto(conn);
4084   retcode = ftp_init(conn);
4085   if(retcode)
4086     return retcode;
4087
4088   if(conn->data->set.wildcardmatch) {
4089     retcode = wc_statemach(conn);
4090     if(conn->data->wildcard.state == CURLWC_SKIP ||
4091       conn->data->wildcard.state == CURLWC_DONE) {
4092       /* do not call ftp_regular_transfer */
4093       return CURLE_OK;
4094     }
4095     if(retcode) /* error, loop or skipping the file */
4096       return retcode;
4097   }
4098   else { /* no wildcard FSM needed */
4099     retcode = ftp_parse_url_path(conn);
4100     if(retcode)
4101       return retcode;
4102   }
4103
4104   retcode = ftp_regular_transfer(conn, done);
4105
4106   return retcode;
4107 }
4108
4109
4110 CURLcode Curl_ftpsendf(struct connectdata *conn,
4111                        const char *fmt, ...)
4112 {
4113   ssize_t bytes_written;
4114 #define SBUF_SIZE 1024
4115   char s[SBUF_SIZE];
4116   size_t write_len;
4117   char *sptr=s;
4118   CURLcode res = CURLE_OK;
4119 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4120   enum protection_level data_sec = conn->data_prot;
4121 #endif
4122
4123   va_list ap;
4124   va_start(ap, fmt);
4125   write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap);
4126   va_end(ap);
4127
4128   strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
4129   write_len +=2;
4130
4131   bytes_written=0;
4132
4133   res = Curl_convert_to_network(conn->data, s, write_len);
4134   /* Curl_convert_to_network calls failf if unsuccessful */
4135   if(res)
4136     return(res);
4137
4138   for(;;) {
4139 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4140     conn->data_prot = PROT_CMD;
4141 #endif
4142     res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
4143                      &bytes_written);
4144 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4145     DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
4146     conn->data_prot = data_sec;
4147 #endif
4148
4149     if(CURLE_OK != res)
4150       break;
4151
4152     if(conn->data->set.verbose)
4153       Curl_debug(conn->data, CURLINFO_HEADER_OUT,
4154                  sptr, (size_t)bytes_written, conn);
4155
4156     if(bytes_written != (ssize_t)write_len) {
4157       write_len -= bytes_written;
4158       sptr += bytes_written;
4159     }
4160     else
4161       break;
4162   }
4163
4164   return res;
4165 }
4166
4167 /***********************************************************************
4168  *
4169  * ftp_quit()
4170  *
4171  * This should be called before calling sclose() on an ftp control connection
4172  * (not data connections). We should then wait for the response from the
4173  * server before returning. The calling code should then try to close the
4174  * connection.
4175  *
4176  */
4177 static CURLcode ftp_quit(struct connectdata *conn)
4178 {
4179   CURLcode result = CURLE_OK;
4180
4181   if(conn->proto.ftpc.ctl_valid) {
4182     result = Curl_pp_sendf(&conn->proto.ftpc.pp, "QUIT", NULL);
4183     if(result) {
4184       failf(conn->data, "Failure sending QUIT command: %s",
4185             curl_easy_strerror(result));
4186       conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
4187       conn->bits.close = TRUE; /* mark for connection closure */
4188       state(conn, FTP_STOP);
4189       return result;
4190     }
4191
4192     state(conn, FTP_QUIT);
4193
4194     result = ftp_block_statemach(conn);
4195   }
4196
4197   return result;
4198 }
4199
4200 /***********************************************************************
4201  *
4202  * ftp_disconnect()
4203  *
4204  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4205  * resources. BLOCKING.
4206  */
4207 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
4208 {
4209   struct ftp_conn *ftpc= &conn->proto.ftpc;
4210   struct pingpong *pp = &ftpc->pp;
4211
4212   /* We cannot send quit unconditionally. If this connection is stale or
4213      bad in any way, sending quit and waiting around here will make the
4214      disconnect wait in vain and cause more problems than we need to.
4215
4216      ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
4217      will try to send the QUIT command, otherwise it will just return.
4218   */
4219   if(dead_connection)
4220     ftpc->ctl_valid = FALSE;
4221
4222   /* The FTP session may or may not have been allocated/setup at this point! */
4223   (void)ftp_quit(conn); /* ignore errors on the QUIT */
4224
4225   if(ftpc->entrypath) {
4226     struct SessionHandle *data = conn->data;
4227     if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
4228       data->state.most_recent_ftp_entrypath = NULL;
4229     }
4230     free(ftpc->entrypath);
4231     ftpc->entrypath = NULL;
4232   }
4233
4234   freedirs(ftpc);
4235   if(ftpc->prevpath) {
4236     free(ftpc->prevpath);
4237     ftpc->prevpath = NULL;
4238   }
4239   if(ftpc->server_os) {
4240     free(ftpc->server_os);
4241     ftpc->server_os = NULL;
4242   }
4243
4244   Curl_pp_disconnect(pp);
4245
4246 #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
4247   Curl_sec_end(conn);
4248 #endif
4249
4250   return CURLE_OK;
4251 }
4252
4253 /***********************************************************************
4254  *
4255  * ftp_parse_url_path()
4256  *
4257  * Parse the URL path into separate path components.
4258  *
4259  */
4260 static
4261 CURLcode ftp_parse_url_path(struct connectdata *conn)
4262 {
4263   struct SessionHandle *data = conn->data;
4264   /* the ftp struct is already inited in ftp_connect() */
4265   struct FTP *ftp = data->state.proto.ftp;
4266   struct ftp_conn *ftpc = &conn->proto.ftpc;
4267   const char *slash_pos;  /* position of the first '/' char in curpos */
4268   const char *path_to_use = data->state.path;
4269   const char *cur_pos;
4270   const char *filename = NULL;
4271
4272   cur_pos = path_to_use; /* current position in path. point at the begin
4273                             of next path component */
4274
4275   ftpc->ctl_valid = FALSE;
4276   ftpc->cwdfail = FALSE;
4277
4278   switch(data->set.ftp_filemethod) {
4279   case FTPFILE_NOCWD:
4280     /* fastest, but less standard-compliant */
4281
4282     /*
4283       The best time to check whether the path is a file or directory is right
4284       here. so:
4285
4286       the first condition in the if() right here, is there just in case
4287       someone decides to set path to NULL one day
4288    */
4289     if(data->state.path &&
4290        data->state.path[0] &&
4291        (data->state.path[strlen(data->state.path) - 1] != '/') )
4292       filename = data->state.path;  /* this is a full file path */
4293       /*
4294         ftpc->file is not used anywhere other than for operations on a file.
4295         In other words, never for directory operations.
4296         So we can safely leave filename as NULL here and use it as a
4297         argument in dir/file decisions.
4298       */
4299     break;
4300
4301   case FTPFILE_SINGLECWD:
4302     /* get the last slash */
4303     if(!path_to_use[0]) {
4304       /* no dir, no file */
4305       ftpc->dirdepth = 0;
4306       break;
4307     }
4308     slash_pos=strrchr(cur_pos, '/');
4309     if(slash_pos || !*cur_pos) {
4310       ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
4311       if(!ftpc->dirs)
4312         return CURLE_OUT_OF_MEMORY;
4313
4314       ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
4315                                          slash_pos ?
4316                                          curlx_sztosi(slash_pos-cur_pos) : 1,
4317                                          NULL);
4318       if(!ftpc->dirs[0]) {
4319         freedirs(ftpc);
4320         return CURLE_OUT_OF_MEMORY;
4321       }
4322       ftpc->dirdepth = 1; /* we consider it to be a single dir */
4323       filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
4324     }
4325     else
4326       filename = cur_pos;  /* this is a file name only */
4327     break;
4328
4329   default: /* allow pretty much anything */
4330   case FTPFILE_MULTICWD:
4331     ftpc->dirdepth = 0;
4332     ftpc->diralloc = 5; /* default dir depth to allocate */
4333     ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
4334     if(!ftpc->dirs)
4335       return CURLE_OUT_OF_MEMORY;
4336
4337     /* we have a special case for listing the root dir only */
4338     if(strequal(path_to_use, "/")) {
4339       cur_pos++; /* make it point to the zero byte */
4340       ftpc->dirs[0] = strdup("/");
4341       ftpc->dirdepth++;
4342     }
4343     else {
4344       /* parse the URL path into separate path components */
4345       while((slash_pos = strchr(cur_pos, '/')) != NULL) {
4346         /* 1 or 0 pointer offset to indicate absolute directory */
4347         ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
4348                                 (ftpc->dirdepth == 0))?1:0;
4349
4350         /* seek out the next path component */
4351         if(slash_pos-cur_pos) {
4352           /* we skip empty path components, like "x//y" since the FTP command
4353              CWD requires a parameter and a non-existent parameter a) doesn't
4354              work on many servers and b) has no effect on the others. */
4355           int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
4356           ftpc->dirs[ftpc->dirdepth] =
4357             curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
4358           if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
4359             failf(data, "no memory");
4360             freedirs(ftpc);
4361             return CURLE_OUT_OF_MEMORY;
4362           }
4363           if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
4364             free(ftpc->dirs[ftpc->dirdepth]);
4365             freedirs(ftpc);
4366             return CURLE_URL_MALFORMAT;
4367           }
4368         }
4369         else {
4370           cur_pos = slash_pos + 1; /* jump to the rest of the string */
4371           continue;
4372         }
4373
4374         cur_pos = slash_pos + 1; /* jump to the rest of the string */
4375         if(++ftpc->dirdepth >= ftpc->diralloc) {
4376           /* enlarge array */
4377           char **bigger;
4378           ftpc->diralloc *= 2; /* double the size each time */
4379           bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
4380           if(!bigger) {
4381             freedirs(ftpc);
4382             return CURLE_OUT_OF_MEMORY;
4383           }
4384           ftpc->dirs = bigger;
4385         }
4386       }
4387     }
4388     filename = cur_pos;  /* the rest is the file name */
4389     break;
4390   } /* switch */
4391
4392   if(filename && *filename) {
4393     ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
4394     if(NULL == ftpc->file) {
4395       freedirs(ftpc);
4396       failf(data, "no memory");
4397       return CURLE_OUT_OF_MEMORY;
4398     }
4399     if(isBadFtpString(ftpc->file)) {
4400       freedirs(ftpc);
4401       return CURLE_URL_MALFORMAT;
4402     }
4403   }
4404   else
4405     ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
4406                        pointer */
4407
4408   if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
4409     /* We need a file name when uploading. Return error! */
4410     failf(data, "Uploading to a URL without a file name!");
4411     return CURLE_URL_MALFORMAT;
4412   }
4413
4414   ftpc->cwddone = FALSE; /* default to not done */
4415
4416   if(ftpc->prevpath) {
4417     /* prevpath is "raw" so we convert the input path before we compare the
4418        strings */
4419     int dlen;
4420     char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
4421     if(!path) {
4422       freedirs(ftpc);
4423       return CURLE_OUT_OF_MEMORY;
4424     }
4425
4426     dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
4427     if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
4428        strnequal(path, ftpc->prevpath, dlen)) {
4429       infof(data, "Request has same path as previous transfer\n");
4430       ftpc->cwddone = TRUE;
4431     }
4432     free(path);
4433   }
4434
4435   return CURLE_OK;
4436 }
4437
4438 /* call this when the DO phase has completed */
4439 static CURLcode ftp_dophase_done(struct connectdata *conn,
4440                                  bool connected)
4441 {
4442   struct FTP *ftp = conn->data->state.proto.ftp;
4443   struct ftp_conn *ftpc = &conn->proto.ftpc;
4444
4445   if(connected) {
4446     bool completed;
4447     CURLcode result = ftp_do_more(conn, &completed);
4448
4449     if(result) {
4450       if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
4451         /* close the second socket if it was created already */
4452         Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
4453         conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4454       }
4455       return result;
4456     }
4457   }
4458
4459   if(ftp->transfer != FTPTRANSFER_BODY)
4460     /* no data to transfer */
4461     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
4462   else if(!connected)
4463     /* since we didn't connect now, we want do_more to get called */
4464     conn->bits.do_more = TRUE;
4465
4466   ftpc->ctl_valid = TRUE; /* seems good */
4467
4468   return CURLE_OK;
4469 }
4470
4471 /* called from multi.c while DOing */
4472 static CURLcode ftp_doing(struct connectdata *conn,
4473                           bool *dophase_done)
4474 {
4475   CURLcode result = ftp_multi_statemach(conn, dophase_done);
4476
4477   if(result)
4478     DEBUGF(infof(conn->data, "DO phase failed\n"));
4479   else if(*dophase_done) {
4480     result = ftp_dophase_done(conn, FALSE /* not connected */);
4481
4482     DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4483   }
4484   return result;
4485 }
4486
4487 /***********************************************************************
4488  *
4489  * ftp_regular_transfer()
4490  *
4491  * The input argument is already checked for validity.
4492  *
4493  * Performs all commands done before a regular transfer between a local and a
4494  * remote host.
4495  *
4496  * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4497  * ftp_done() function without finding any major problem.
4498  */
4499 static
4500 CURLcode ftp_regular_transfer(struct connectdata *conn,
4501                               bool *dophase_done)
4502 {
4503   CURLcode result=CURLE_OK;
4504   bool connected=FALSE;
4505   struct SessionHandle *data = conn->data;
4506   struct ftp_conn *ftpc = &conn->proto.ftpc;
4507   data->req.size = -1; /* make sure this is unknown at this point */
4508
4509   Curl_pgrsSetUploadCounter(data, 0);
4510   Curl_pgrsSetDownloadCounter(data, 0);
4511   Curl_pgrsSetUploadSize(data, 0);
4512   Curl_pgrsSetDownloadSize(data, 0);
4513
4514   ftpc->ctl_valid = TRUE; /* starts good */
4515
4516   result = ftp_perform(conn,
4517                        &connected, /* have we connected after PASV/PORT */
4518                        dophase_done); /* all commands in the DO-phase done? */
4519
4520   if(CURLE_OK == result) {
4521
4522     if(!*dophase_done)
4523       /* the DO phase has not completed yet */
4524       return CURLE_OK;
4525
4526     result = ftp_dophase_done(conn, connected);
4527
4528     if(result)
4529       return result;
4530   }
4531   else
4532     freedirs(ftpc);
4533
4534   return result;
4535 }
4536
4537 static CURLcode ftp_setup_connection(struct connectdata * conn)
4538 {
4539   struct SessionHandle *data = conn->data;
4540   char * type;
4541   char command;
4542
4543   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
4544     /* Unless we have asked to tunnel ftp operations through the proxy, we
4545        switch and use HTTP operations only */
4546 #ifndef CURL_DISABLE_HTTP
4547     if(conn->handler == &Curl_handler_ftp)
4548       conn->handler = &Curl_handler_ftp_proxy;
4549     else {
4550 #ifdef USE_SSL
4551       conn->handler = &Curl_handler_ftps_proxy;
4552 #else
4553       failf(data, "FTPS not supported!");
4554       return CURLE_UNSUPPORTED_PROTOCOL;
4555 #endif
4556     }
4557     /*
4558      * We explicitly mark this connection as persistent here as we're doing
4559      * FTP over HTTP and thus we accidentally avoid setting this value
4560      * otherwise.
4561      */
4562     conn->bits.close = FALSE;
4563 #else
4564     failf(data, "FTP over http proxy requires HTTP support built-in!");
4565     return CURLE_UNSUPPORTED_PROTOCOL;
4566 #endif
4567   }
4568
4569   data->state.path++;   /* don't include the initial slash */
4570   data->state.slash_removed = TRUE; /* we've skipped the slash */
4571
4572   /* FTP URLs support an extension like ";type=<typecode>" that
4573    * we'll try to get now! */
4574   type = strstr(data->state.path, ";type=");
4575
4576   if(!type)
4577     type = strstr(conn->host.rawalloc, ";type=");
4578
4579   if(type) {
4580     *type = 0;                     /* it was in the middle of the hostname */
4581     command = Curl_raw_toupper(type[6]);
4582     conn->bits.type_set = TRUE;
4583
4584     switch (command) {
4585     case 'A': /* ASCII mode */
4586       data->set.prefer_ascii = TRUE;
4587       break;
4588
4589     case 'D': /* directory mode */
4590       data->set.ftp_list_only = TRUE;
4591       break;
4592
4593     case 'I': /* binary mode */
4594     default:
4595       /* switch off ASCII */
4596       data->set.prefer_ascii = FALSE;
4597       break;
4598     }
4599   }
4600
4601   return CURLE_OK;
4602 }
4603
4604 #endif /* CURL_DISABLE_FTP */