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