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