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