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