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