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