ftp.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #ifndef CURL_DISABLE_FTP
00026 
00027 #ifdef HAVE_NETINET_IN_H
00028 #include <netinet/in.h>
00029 #endif
00030 #ifdef HAVE_ARPA_INET_H
00031 #include <arpa/inet.h>
00032 #endif
00033 #ifdef HAVE_UTSNAME_H
00034 #include <sys/utsname.h>
00035 #endif
00036 #ifdef HAVE_NETDB_H
00037 #include <netdb.h>
00038 #endif
00039 #ifdef __VMS
00040 #include <in.h>
00041 #include <inet.h>
00042 #endif
00043 
00044 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
00045 #undef in_addr_t
00046 #define in_addr_t unsigned long
00047 #endif
00048 
00049 #include <curl/curl.h>
00050 #include "urldata.h"
00051 #include "sendf.h"
00052 #include "if2ip.h"
00053 #include "hostip.h"
00054 #include "progress.h"
00055 #include "transfer.h"
00056 #include "escape.h"
00057 #include "http.h" /* for HTTP proxy tunnel stuff */
00058 #include "socks.h"
00059 #include "ftp.h"
00060 #include "fileinfo.h"
00061 #include "ftplistparser.h"
00062 #include "curl_sec.h"
00063 #include "strtoofft.h"
00064 #include "strcase.h"
00065 #include "vtls/vtls.h"
00066 #include "connect.h"
00067 #include "strerror.h"
00068 #include "inet_ntop.h"
00069 #include "inet_pton.h"
00070 #include "select.h"
00071 #include "parsedate.h" /* for the week day and month names */
00072 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
00073 #include "multiif.h"
00074 #include "url.h"
00075 #include "strcase.h"
00076 #include "speedcheck.h"
00077 #include "warnless.h"
00078 #include "http_proxy.h"
00079 #include "non-ascii.h"
00080 /* The last 3 #include files should be in this order */
00081 #include "curl_printf.h"
00082 #include "curl_memory.h"
00083 #include "memdebug.h"
00084 
00085 #ifndef NI_MAXHOST
00086 #define NI_MAXHOST 1025
00087 #endif
00088 #ifndef INET_ADDRSTRLEN
00089 #define INET_ADDRSTRLEN 16
00090 #endif
00091 
00092 #ifdef CURL_DISABLE_VERBOSE_STRINGS
00093 #define ftp_pasv_verbose(a,b,c,d)  Curl_nop_stmt
00094 #endif
00095 
00096 /* Local API functions */
00097 #ifndef DEBUGBUILD
00098 static void _state(struct connectdata *conn,
00099                    ftpstate newstate);
00100 #define state(x,y) _state(x,y)
00101 #else
00102 static void _state(struct connectdata *conn,
00103                    ftpstate newstate,
00104                    int lineno);
00105 #define state(x,y) _state(x,y,__LINE__)
00106 #endif
00107 
00108 static CURLcode ftp_sendquote(struct connectdata *conn,
00109                               struct curl_slist *quote);
00110 static CURLcode ftp_quit(struct connectdata *conn);
00111 static CURLcode ftp_parse_url_path(struct connectdata *conn);
00112 static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
00113 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00114 static void ftp_pasv_verbose(struct connectdata *conn,
00115                              Curl_addrinfo *ai,
00116                              char *newhost, /* ascii version */
00117                              int port);
00118 #endif
00119 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
00120 static CURLcode ftp_state_mdtm(struct connectdata *conn);
00121 static CURLcode ftp_state_quote(struct connectdata *conn,
00122                                 bool init, ftpstate instate);
00123 static CURLcode ftp_nb_type(struct connectdata *conn,
00124                             bool ascii, ftpstate newstate);
00125 static int ftp_need_type(struct connectdata *conn,
00126                          bool ascii);
00127 static CURLcode ftp_do(struct connectdata *conn, bool *done);
00128 static CURLcode ftp_done(struct connectdata *conn,
00129                          CURLcode, bool premature);
00130 static CURLcode ftp_connect(struct connectdata *conn, bool *done);
00131 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
00132 static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
00133 static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
00134 static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
00135                        int numsocks);
00136 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
00137                               int numsocks);
00138 static CURLcode ftp_doing(struct connectdata *conn,
00139                           bool *dophase_done);
00140 static CURLcode ftp_setup_connection(struct connectdata * conn);
00141 
00142 static CURLcode init_wc_data(struct connectdata *conn);
00143 static CURLcode wc_statemach(struct connectdata *conn);
00144 
00145 static void wc_data_dtor(void *ptr);
00146 
00147 static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
00148 
00149 static CURLcode ftp_readresp(curl_socket_t sockfd,
00150                              struct pingpong *pp,
00151                              int *ftpcode,
00152                              size_t *size);
00153 static CURLcode ftp_dophase_done(struct connectdata *conn,
00154                                  bool connected);
00155 
00156 /* easy-to-use macro: */
00157 #define PPSENDF(x,y,z)  result = Curl_pp_sendf(x,y,z); \
00158                         if(result)                     \
00159                           return result
00160 
00161 
00162 /*
00163  * FTP protocol handler.
00164  */
00165 
00166 const struct Curl_handler Curl_handler_ftp = {
00167   "FTP",                           /* scheme */
00168   ftp_setup_connection,            /* setup_connection */
00169   ftp_do,                          /* do_it */
00170   ftp_done,                        /* done */
00171   ftp_do_more,                     /* do_more */
00172   ftp_connect,                     /* connect_it */
00173   ftp_multi_statemach,             /* connecting */
00174   ftp_doing,                       /* doing */
00175   ftp_getsock,                     /* proto_getsock */
00176   ftp_getsock,                     /* doing_getsock */
00177   ftp_domore_getsock,              /* domore_getsock */
00178   ZERO_NULL,                       /* perform_getsock */
00179   ftp_disconnect,                  /* disconnect */
00180   ZERO_NULL,                       /* readwrite */
00181   PORT_FTP,                        /* defport */
00182   CURLPROTO_FTP,                   /* protocol */
00183   PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
00184   | PROTOPT_NOURLQUERY /* flags */
00185 };
00186 
00187 
00188 #ifdef USE_SSL
00189 /*
00190  * FTPS protocol handler.
00191  */
00192 
00193 const struct Curl_handler Curl_handler_ftps = {
00194   "FTPS",                          /* scheme */
00195   ftp_setup_connection,            /* setup_connection */
00196   ftp_do,                          /* do_it */
00197   ftp_done,                        /* done */
00198   ftp_do_more,                     /* do_more */
00199   ftp_connect,                     /* connect_it */
00200   ftp_multi_statemach,             /* connecting */
00201   ftp_doing,                       /* doing */
00202   ftp_getsock,                     /* proto_getsock */
00203   ftp_getsock,                     /* doing_getsock */
00204   ftp_domore_getsock,              /* domore_getsock */
00205   ZERO_NULL,                       /* perform_getsock */
00206   ftp_disconnect,                  /* disconnect */
00207   ZERO_NULL,                       /* readwrite */
00208   PORT_FTPS,                       /* defport */
00209   CURLPROTO_FTPS,                  /* protocol */
00210   PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
00211   PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
00212 };
00213 #endif
00214 
00215 #ifndef CURL_DISABLE_HTTP
00216 /*
00217  * HTTP-proxyed FTP protocol handler.
00218  */
00219 
00220 static const struct Curl_handler Curl_handler_ftp_proxy = {
00221   "FTP",                                /* scheme */
00222   Curl_http_setup_conn,                 /* setup_connection */
00223   Curl_http,                            /* do_it */
00224   Curl_http_done,                       /* done */
00225   ZERO_NULL,                            /* do_more */
00226   ZERO_NULL,                            /* connect_it */
00227   ZERO_NULL,                            /* connecting */
00228   ZERO_NULL,                            /* doing */
00229   ZERO_NULL,                            /* proto_getsock */
00230   ZERO_NULL,                            /* doing_getsock */
00231   ZERO_NULL,                            /* domore_getsock */
00232   ZERO_NULL,                            /* perform_getsock */
00233   ZERO_NULL,                            /* disconnect */
00234   ZERO_NULL,                            /* readwrite */
00235   PORT_FTP,                             /* defport */
00236   CURLPROTO_HTTP,                       /* protocol */
00237   PROTOPT_NONE                          /* flags */
00238 };
00239 
00240 
00241 #ifdef USE_SSL
00242 /*
00243  * HTTP-proxyed FTPS protocol handler.
00244  */
00245 
00246 static const struct Curl_handler Curl_handler_ftps_proxy = {
00247   "FTPS",                               /* scheme */
00248   Curl_http_setup_conn,                 /* setup_connection */
00249   Curl_http,                            /* do_it */
00250   Curl_http_done,                       /* done */
00251   ZERO_NULL,                            /* do_more */
00252   ZERO_NULL,                            /* connect_it */
00253   ZERO_NULL,                            /* connecting */
00254   ZERO_NULL,                            /* doing */
00255   ZERO_NULL,                            /* proto_getsock */
00256   ZERO_NULL,                            /* doing_getsock */
00257   ZERO_NULL,                            /* domore_getsock */
00258   ZERO_NULL,                            /* perform_getsock */
00259   ZERO_NULL,                            /* disconnect */
00260   ZERO_NULL,                            /* readwrite */
00261   PORT_FTPS,                            /* defport */
00262   CURLPROTO_HTTP,                       /* protocol */
00263   PROTOPT_NONE                          /* flags */
00264 };
00265 #endif
00266 #endif
00267 
00268 static void close_secondarysocket(struct connectdata *conn)
00269 {
00270   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
00271     Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
00272     conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
00273   }
00274   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
00275   conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT;
00276 }
00277 
00278 /*
00279  * NOTE: back in the old days, we added code in the FTP code that made NOBODY
00280  * requests on files respond with headers passed to the client/stdout that
00281  * looked like HTTP ones.
00282  *
00283  * This approach is not very elegant, it causes confusion and is error-prone.
00284  * It is subject for removal at the next (or at least a future) soname bump.
00285  * Until then you can test the effects of the removal by undefining the
00286  * following define named CURL_FTP_HTTPSTYLE_HEAD.
00287  */
00288 #define CURL_FTP_HTTPSTYLE_HEAD 1
00289 
00290 static void freedirs(struct ftp_conn *ftpc)
00291 {
00292   int i;
00293   if(ftpc->dirs) {
00294     for(i=0; i < ftpc->dirdepth; i++) {
00295       free(ftpc->dirs[i]);
00296       ftpc->dirs[i]=NULL;
00297     }
00298     free(ftpc->dirs);
00299     ftpc->dirs = NULL;
00300     ftpc->dirdepth = 0;
00301   }
00302   Curl_safefree(ftpc->file);
00303 
00304   /* no longer of any use */
00305   Curl_safefree(ftpc->newhost);
00306 }
00307 
00308 /* Returns non-zero if the given string contains CR (\r) or LF (\n),
00309    which are not allowed within RFC 959 <string>.
00310    Note: The input string is in the client's encoding which might
00311    not be ASCII, so escape sequences \r & \n must be used instead
00312    of hex values 0x0d & 0x0a.
00313 */
00314 static bool isBadFtpString(const char *string)
00315 {
00316   return ((NULL != strchr(string, '\r')) ||
00317           (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
00318 }
00319 
00320 /***********************************************************************
00321  *
00322  * AcceptServerConnect()
00323  *
00324  * After connection request is received from the server this function is
00325  * called to accept the connection and close the listening socket
00326  *
00327  */
00328 static CURLcode AcceptServerConnect(struct connectdata *conn)
00329 {
00330   struct Curl_easy *data = conn->data;
00331   curl_socket_t sock = conn->sock[SECONDARYSOCKET];
00332   curl_socket_t s = CURL_SOCKET_BAD;
00333 #ifdef ENABLE_IPV6
00334   struct Curl_sockaddr_storage add;
00335 #else
00336   struct sockaddr_in add;
00337 #endif
00338   curl_socklen_t size = (curl_socklen_t) sizeof(add);
00339 
00340   if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
00341     size = sizeof(add);
00342 
00343     s=accept(sock, (struct sockaddr *) &add, &size);
00344   }
00345   Curl_closesocket(conn, sock); /* close the first socket */
00346 
00347   if(CURL_SOCKET_BAD == s) {
00348     failf(data, "Error accept()ing server connect");
00349     return CURLE_FTP_PORT_FAILED;
00350   }
00351   infof(data, "Connection accepted from server\n");
00352   /* when this happens within the DO state it is important that we mark us as
00353      not needing DO_MORE anymore */
00354   conn->bits.do_more = FALSE;
00355 
00356   conn->sock[SECONDARYSOCKET] = s;
00357   (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
00358   conn->sock_accepted[SECONDARYSOCKET] = TRUE;
00359 
00360   if(data->set.fsockopt) {
00361     int error = 0;
00362 
00363     /* activate callback for setting socket options */
00364     error = data->set.fsockopt(data->set.sockopt_client,
00365                                s,
00366                                CURLSOCKTYPE_ACCEPT);
00367 
00368     if(error) {
00369       close_secondarysocket(conn);
00370       return CURLE_ABORTED_BY_CALLBACK;
00371     }
00372   }
00373 
00374   return CURLE_OK;
00375 
00376 }
00377 
00378 /*
00379  * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
00380  * waiting server to connect. If the value is negative, the timeout time has
00381  * already elapsed.
00382  *
00383  * The start time is stored in progress.t_acceptdata - as set with
00384  * Curl_pgrsTime(..., TIMER_STARTACCEPT);
00385  *
00386  */
00387 static time_t ftp_timeleft_accept(struct Curl_easy *data)
00388 {
00389   time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
00390   time_t other;
00391   struct timeval now;
00392 
00393   if(data->set.accepttimeout > 0)
00394     timeout_ms = data->set.accepttimeout;
00395 
00396   now = Curl_tvnow();
00397 
00398   /* check if the generic timeout possibly is set shorter */
00399   other =  Curl_timeleft(data, &now, FALSE);
00400   if(other && (other < timeout_ms))
00401     /* note that this also works fine for when other happens to be negative
00402        due to it already having elapsed */
00403     timeout_ms = other;
00404   else {
00405     /* subtract elapsed time */
00406     timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
00407     if(!timeout_ms)
00408       /* avoid returning 0 as that means no timeout! */
00409       return -1;
00410   }
00411 
00412   return timeout_ms;
00413 }
00414 
00415 
00416 /***********************************************************************
00417  *
00418  * ReceivedServerConnect()
00419  *
00420  * After allowing server to connect to us from data port, this function
00421  * checks both data connection for connection establishment and ctrl
00422  * connection for a negative response regarding a failure in connecting
00423  *
00424  */
00425 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
00426 {
00427   struct Curl_easy *data = conn->data;
00428   curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
00429   curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
00430   struct ftp_conn *ftpc = &conn->proto.ftpc;
00431   struct pingpong *pp = &ftpc->pp;
00432   int result;
00433   time_t timeout_ms;
00434   ssize_t nread;
00435   int ftpcode;
00436 
00437   *received = FALSE;
00438 
00439   timeout_ms = ftp_timeleft_accept(data);
00440   infof(data, "Checking for server connect\n");
00441   if(timeout_ms < 0) {
00442     /* if a timeout was already reached, bail out */
00443     failf(data, "Accept timeout occurred while waiting server connect");
00444     return CURLE_FTP_ACCEPT_TIMEOUT;
00445   }
00446 
00447   /* First check whether there is a cached response from server */
00448   if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
00449     /* Data connection could not be established, let's return */
00450     infof(data, "There is negative response in cache while serv connect\n");
00451     Curl_GetFTPResponse(&nread, conn, &ftpcode);
00452     return CURLE_FTP_ACCEPT_FAILED;
00453   }
00454 
00455   result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
00456 
00457   /* see if the connection request is already here */
00458   switch(result) {
00459   case -1: /* error */
00460     /* let's die here */
00461     failf(data, "Error while waiting for server connect");
00462     return CURLE_FTP_ACCEPT_FAILED;
00463   case 0:  /* Server connect is not received yet */
00464     break; /* loop */
00465   default:
00466 
00467     if(result & CURL_CSELECT_IN2) {
00468       infof(data, "Ready to accept data connection from server\n");
00469       *received = TRUE;
00470     }
00471     else if(result & CURL_CSELECT_IN) {
00472       infof(data, "Ctrl conn has data while waiting for data conn\n");
00473       Curl_GetFTPResponse(&nread, conn, &ftpcode);
00474 
00475       if(ftpcode/100 > 3)
00476         return CURLE_FTP_ACCEPT_FAILED;
00477 
00478       return CURLE_WEIRD_SERVER_REPLY;
00479     }
00480 
00481     break;
00482   } /* switch() */
00483 
00484   return CURLE_OK;
00485 }
00486 
00487 
00488 /***********************************************************************
00489  *
00490  * InitiateTransfer()
00491  *
00492  * After connection from server is accepted this function is called to
00493  * setup transfer parameters and initiate the data transfer.
00494  *
00495  */
00496 static CURLcode InitiateTransfer(struct connectdata *conn)
00497 {
00498   struct Curl_easy *data = conn->data;
00499   struct FTP *ftp = data->req.protop;
00500   CURLcode result = CURLE_OK;
00501 
00502   if(conn->bits.ftp_use_data_ssl) {
00503     /* since we only have a plaintext TCP connection here, we must now
00504      * do the TLS stuff */
00505     infof(data, "Doing the SSL/TLS handshake on the data stream\n");
00506     result = Curl_ssl_connect(conn, SECONDARYSOCKET);
00507     if(result)
00508       return result;
00509   }
00510 
00511   if(conn->proto.ftpc.state_saved == FTP_STOR) {
00512     *(ftp->bytecountp)=0;
00513 
00514     /* When we know we're uploading a specified file, we can get the file
00515        size prior to the actual upload. */
00516 
00517     Curl_pgrsSetUploadSize(data, data->state.infilesize);
00518 
00519     /* set the SO_SNDBUF for the secondary socket for those who need it */
00520     Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
00521 
00522     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
00523                         SECONDARYSOCKET, ftp->bytecountp);
00524   }
00525   else {
00526     /* FTP download: */
00527     Curl_setup_transfer(conn, SECONDARYSOCKET,
00528                         conn->proto.ftpc.retr_size_saved, FALSE,
00529                         ftp->bytecountp, -1, NULL); /* no upload here */
00530   }
00531 
00532   conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
00533   state(conn, FTP_STOP);
00534 
00535   return CURLE_OK;
00536 }
00537 
00538 /***********************************************************************
00539  *
00540  * AllowServerConnect()
00541  *
00542  * When we've issue the PORT command, we have told the server to connect to
00543  * us. This function checks whether data connection is established if so it is
00544  * accepted.
00545  *
00546  */
00547 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
00548 {
00549   struct Curl_easy *data = conn->data;
00550   time_t timeout_ms;
00551   CURLcode result = CURLE_OK;
00552 
00553   *connected = FALSE;
00554   infof(data, "Preparing for accepting server on data port\n");
00555 
00556   /* Save the time we start accepting server connect */
00557   Curl_pgrsTime(data, TIMER_STARTACCEPT);
00558 
00559   timeout_ms = ftp_timeleft_accept(data);
00560   if(timeout_ms < 0) {
00561     /* if a timeout was already reached, bail out */
00562     failf(data, "Accept timeout occurred while waiting server connect");
00563     return CURLE_FTP_ACCEPT_TIMEOUT;
00564   }
00565 
00566   /* see if the connection request is already here */
00567   result = ReceivedServerConnect(conn, connected);
00568   if(result)
00569     return result;
00570 
00571   if(*connected) {
00572     result = AcceptServerConnect(conn);
00573     if(result)
00574       return result;
00575 
00576     result = InitiateTransfer(conn);
00577     if(result)
00578       return result;
00579   }
00580   else {
00581     /* Add timeout to multi handle and break out of the loop */
00582     if(!result && *connected == FALSE) {
00583       if(data->set.accepttimeout > 0)
00584         Curl_expire(data, data->set.accepttimeout);
00585       else
00586         Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
00587     }
00588   }
00589 
00590   return result;
00591 }
00592 
00593 /* macro to check for a three-digit ftp status code at the start of the
00594    given string */
00595 #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) &&       \
00596                           ISDIGIT(line[2]))
00597 
00598 /* macro to check for the last line in an FTP server response */
00599 #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
00600 
00601 static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
00602                           int *code)
00603 {
00604   (void)conn;
00605 
00606   if((len > 3) && LASTLINE(line)) {
00607     *code = curlx_sltosi(strtol(line, NULL, 10));
00608     return TRUE;
00609   }
00610 
00611   return FALSE;
00612 }
00613 
00614 static CURLcode ftp_readresp(curl_socket_t sockfd,
00615                              struct pingpong *pp,
00616                              int *ftpcode, /* return the ftp-code if done */
00617                              size_t *size) /* size of the response */
00618 {
00619   struct connectdata *conn = pp->conn;
00620   struct Curl_easy *data = conn->data;
00621 #ifdef HAVE_GSSAPI
00622   char * const buf = data->state.buffer;
00623 #endif
00624   CURLcode result = CURLE_OK;
00625   int code;
00626 
00627   result = Curl_pp_readresp(sockfd, pp, &code, size);
00628 
00629 #if defined(HAVE_GSSAPI)
00630   /* handle the security-oriented responses 6xx ***/
00631   /* FIXME: some errorchecking perhaps... ***/
00632   switch(code) {
00633   case 631:
00634     code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
00635     break;
00636   case 632:
00637     code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
00638     break;
00639   case 633:
00640     code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
00641     break;
00642   default:
00643     /* normal ftp stuff we pass through! */
00644     break;
00645   }
00646 #endif
00647 
00648   /* store the latest code for later retrieval */
00649   data->info.httpcode=code;
00650 
00651   if(ftpcode)
00652     *ftpcode = code;
00653 
00654   if(421 == code) {
00655     /* 421 means "Service not available, closing control connection." and FTP
00656      * servers use it to signal that idle session timeout has been exceeded.
00657      * If we ignored the response, it could end up hanging in some cases.
00658      *
00659      * This response code can come at any point so having it treated
00660      * generically is a good idea.
00661      */
00662     infof(data, "We got a 421 - timeout!\n");
00663     state(conn, FTP_STOP);
00664     return CURLE_OPERATION_TIMEDOUT;
00665   }
00666 
00667   return result;
00668 }
00669 
00670 /* --- parse FTP server responses --- */
00671 
00672 /*
00673  * Curl_GetFTPResponse() is a BLOCKING function to read the full response
00674  * from a server after a command.
00675  *
00676  */
00677 
00678 CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
00679                              struct connectdata *conn,
00680                              int *ftpcode) /* return the ftp-code */
00681 {
00682   /*
00683    * We cannot read just one byte per read() and then go back to select() as
00684    * the OpenSSL read() doesn't grok that properly.
00685    *
00686    * Alas, read as much as possible, split up into lines, use the ending
00687    * line in a response or continue reading.  */
00688 
00689   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
00690   time_t timeout;              /* timeout in milliseconds */
00691   time_t interval_ms;
00692   struct Curl_easy *data = conn->data;
00693   CURLcode result = CURLE_OK;
00694   struct ftp_conn *ftpc = &conn->proto.ftpc;
00695   struct pingpong *pp = &ftpc->pp;
00696   size_t nread;
00697   int cache_skip=0;
00698   int value_to_be_ignored=0;
00699 
00700   if(ftpcode)
00701     *ftpcode = 0; /* 0 for errors */
00702   else
00703     /* make the pointer point to something for the rest of this function */
00704     ftpcode = &value_to_be_ignored;
00705 
00706   *nreadp=0;
00707 
00708   while(!*ftpcode && !result) {
00709     /* check and reset timeout value every lap */
00710     timeout = Curl_pp_state_timeout(pp);
00711 
00712     if(timeout <=0) {
00713       failf(data, "FTP response timeout");
00714       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
00715     }
00716 
00717     interval_ms = 1000;  /* use 1 second timeout intervals */
00718     if(timeout < interval_ms)
00719       interval_ms = timeout;
00720 
00721     /*
00722      * Since this function is blocking, we need to wait here for input on the
00723      * connection and only then we call the response reading function. We do
00724      * timeout at least every second to make the timeout check run.
00725      *
00726      * A caution here is that the ftp_readresp() function has a cache that may
00727      * contain pieces of a response from the previous invoke and we need to
00728      * make sure we don't just wait for input while there is unhandled data in
00729      * that cache. But also, if the cache is there, we call ftp_readresp() and
00730      * the cache wasn't good enough to continue we must not just busy-loop
00731      * around this function.
00732      *
00733      */
00734 
00735     if(pp->cache && (cache_skip < 2)) {
00736       /*
00737        * There's a cache left since before. We then skipping the wait for
00738        * socket action, unless this is the same cache like the previous round
00739        * as then the cache was deemed not enough to act on and we then need to
00740        * wait for more data anyway.
00741        */
00742     }
00743     else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
00744       switch(SOCKET_READABLE(sockfd, interval_ms)) {
00745       case -1: /* select() error, stop reading */
00746         failf(data, "FTP response aborted due to select/poll error: %d",
00747               SOCKERRNO);
00748         return CURLE_RECV_ERROR;
00749 
00750       case 0: /* timeout */
00751         if(Curl_pgrsUpdate(conn))
00752           return CURLE_ABORTED_BY_CALLBACK;
00753         continue; /* just continue in our loop for the timeout duration */
00754 
00755       default: /* for clarity */
00756         break;
00757       }
00758     }
00759     result = ftp_readresp(sockfd, pp, ftpcode, &nread);
00760     if(result)
00761       break;
00762 
00763     if(!nread && pp->cache)
00764       /* bump cache skip counter as on repeated skips we must wait for more
00765          data */
00766       cache_skip++;
00767     else
00768       /* when we got data or there is no cache left, we reset the cache skip
00769          counter */
00770       cache_skip=0;
00771 
00772     *nreadp += nread;
00773 
00774   } /* while there's buffer left and loop is requested */
00775 
00776   pp->pending_resp = FALSE;
00777 
00778   return result;
00779 }
00780 
00781 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
00782   /* for debug purposes */
00783 static const char * const ftp_state_names[]={
00784   "STOP",
00785   "WAIT220",
00786   "AUTH",
00787   "USER",
00788   "PASS",
00789   "ACCT",
00790   "PBSZ",
00791   "PROT",
00792   "CCC",
00793   "PWD",
00794   "SYST",
00795   "NAMEFMT",
00796   "QUOTE",
00797   "RETR_PREQUOTE",
00798   "STOR_PREQUOTE",
00799   "POSTQUOTE",
00800   "CWD",
00801   "MKD",
00802   "MDTM",
00803   "TYPE",
00804   "LIST_TYPE",
00805   "RETR_TYPE",
00806   "STOR_TYPE",
00807   "SIZE",
00808   "RETR_SIZE",
00809   "STOR_SIZE",
00810   "REST",
00811   "RETR_REST",
00812   "PORT",
00813   "PRET",
00814   "PASV",
00815   "LIST",
00816   "RETR",
00817   "STOR",
00818   "QUIT"
00819 };
00820 #endif
00821 
00822 /* This is the ONLY way to change FTP state! */
00823 static void _state(struct connectdata *conn,
00824                    ftpstate newstate
00825 #ifdef DEBUGBUILD
00826                    , int lineno
00827 #endif
00828   )
00829 {
00830   struct ftp_conn *ftpc = &conn->proto.ftpc;
00831 
00832 #if defined(DEBUGBUILD)
00833 
00834 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
00835   (void) lineno;
00836 #else
00837   if(ftpc->state != newstate)
00838     infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
00839           (void *)ftpc, lineno, ftp_state_names[ftpc->state],
00840           ftp_state_names[newstate]);
00841 #endif
00842 #endif
00843 
00844   ftpc->state = newstate;
00845 }
00846 
00847 static CURLcode ftp_state_user(struct connectdata *conn)
00848 {
00849   CURLcode result;
00850   struct FTP *ftp = conn->data->req.protop;
00851   /* send USER */
00852   PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
00853 
00854   state(conn, FTP_USER);
00855   conn->data->state.ftp_trying_alternative = FALSE;
00856 
00857   return CURLE_OK;
00858 }
00859 
00860 static CURLcode ftp_state_pwd(struct connectdata *conn)
00861 {
00862   CURLcode result;
00863 
00864   /* send PWD to discover our entry point */
00865   PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
00866   state(conn, FTP_PWD);
00867 
00868   return CURLE_OK;
00869 }
00870 
00871 /* For the FTP "protocol connect" and "doing" phases only */
00872 static int ftp_getsock(struct connectdata *conn,
00873                        curl_socket_t *socks,
00874                        int numsocks)
00875 {
00876   return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
00877 }
00878 
00879 /* For the FTP "DO_MORE" phase only */
00880 static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
00881                               int numsocks)
00882 {
00883   struct ftp_conn *ftpc = &conn->proto.ftpc;
00884 
00885   if(!numsocks)
00886     return GETSOCK_BLANK;
00887 
00888   /* When in DO_MORE state, we could be either waiting for us to connect to a
00889    * remote site, or we could wait for that site to connect to us. Or just
00890    * handle ordinary commands.
00891    */
00892 
00893   if(FTP_STOP == ftpc->state) {
00894     int bits = GETSOCK_READSOCK(0);
00895 
00896     /* if stopped and still in this state, then we're also waiting for a
00897        connect on the secondary connection */
00898     socks[0] = conn->sock[FIRSTSOCKET];
00899 
00900     if(!conn->data->set.ftp_use_port) {
00901       int s;
00902       int i;
00903       /* PORT is used to tell the server to connect to us, and during that we
00904          don't do happy eyeballs, but we do if we connect to the server */
00905       for(s=1, i=0; i<2; i++) {
00906         if(conn->tempsock[i] != CURL_SOCKET_BAD) {
00907           socks[s] = conn->tempsock[i];
00908           bits |= GETSOCK_WRITESOCK(s++);
00909         }
00910       }
00911     }
00912     else {
00913       socks[1] = conn->sock[SECONDARYSOCKET];
00914       bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
00915     }
00916 
00917     return bits;
00918   }
00919   else
00920     return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
00921 }
00922 
00923 /* This is called after the FTP_QUOTE state is passed.
00924 
00925    ftp_state_cwd() sends the range of CWD commands to the server to change to
00926    the correct directory. It may also need to send MKD commands to create
00927    missing ones, if that option is enabled.
00928 */
00929 static CURLcode ftp_state_cwd(struct connectdata *conn)
00930 {
00931   CURLcode result = CURLE_OK;
00932   struct ftp_conn *ftpc = &conn->proto.ftpc;
00933 
00934   if(ftpc->cwddone)
00935     /* already done and fine */
00936     result = ftp_state_mdtm(conn);
00937   else {
00938     ftpc->count2 = 0; /* count2 counts failed CWDs */
00939 
00940     /* count3 is set to allow a MKD to fail once. In the case when first CWD
00941        fails and then MKD fails (due to another session raced it to create the
00942        dir) this then allows for a second try to CWD to it */
00943     ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
00944 
00945     if(conn->bits.reuse && ftpc->entrypath) {
00946       /* This is a re-used connection. Since we change directory to where the
00947          transfer is taking place, we must first get back to the original dir
00948          where we ended up after login: */
00949       ftpc->count1 = 0; /* we count this as the first path, then we add one
00950                           for all upcoming ones in the ftp->dirs[] array */
00951       PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
00952       state(conn, FTP_CWD);
00953     }
00954     else {
00955       if(ftpc->dirdepth) {
00956         ftpc->count1 = 1;
00957         /* issue the first CWD, the rest is sent when the CWD responses are
00958            received... */
00959         PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
00960         state(conn, FTP_CWD);
00961       }
00962       else {
00963         /* No CWD necessary */
00964         result = ftp_state_mdtm(conn);
00965       }
00966     }
00967   }
00968   return result;
00969 }
00970 
00971 typedef enum {
00972   EPRT,
00973   PORT,
00974   DONE
00975 } ftpport;
00976 
00977 static CURLcode ftp_state_use_port(struct connectdata *conn,
00978                                    ftpport fcmd) /* start with this */
00979 
00980 {
00981   CURLcode result = CURLE_OK;
00982   struct ftp_conn *ftpc = &conn->proto.ftpc;
00983   struct Curl_easy *data=conn->data;
00984   curl_socket_t portsock= CURL_SOCKET_BAD;
00985   char myhost[256] = "";
00986 
00987   struct Curl_sockaddr_storage ss;
00988   Curl_addrinfo *res, *ai;
00989   curl_socklen_t sslen;
00990   char hbuf[NI_MAXHOST];
00991   struct sockaddr *sa=(struct sockaddr *)&ss;
00992   struct sockaddr_in * const sa4 = (void *)sa;
00993 #ifdef ENABLE_IPV6
00994   struct sockaddr_in6 * const sa6 = (void *)sa;
00995 #endif
00996   char tmp[1024];
00997   static const char mode[][5] = { "EPRT", "PORT" };
00998   int rc;
00999   int error;
01000   char *host = NULL;
01001   char *string_ftpport = data->set.str[STRING_FTPPORT];
01002   struct Curl_dns_entry *h=NULL;
01003   unsigned short port_min = 0;
01004   unsigned short port_max = 0;
01005   unsigned short port;
01006   bool possibly_non_local = TRUE;
01007 
01008   char *addr = NULL;
01009 
01010   /* Step 1, figure out what is requested,
01011    * accepted format :
01012    * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
01013    */
01014 
01015   if(data->set.str[STRING_FTPPORT] &&
01016      (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
01017 
01018 #ifdef ENABLE_IPV6
01019     size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
01020       INET6_ADDRSTRLEN : strlen(string_ftpport);
01021 #else
01022     size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
01023       INET_ADDRSTRLEN : strlen(string_ftpport);
01024 #endif
01025     char *ip_start = string_ftpport;
01026     char *ip_end = NULL;
01027     char *port_start = NULL;
01028     char *port_sep = NULL;
01029 
01030     addr = calloc(addrlen+1, 1);
01031     if(!addr)
01032       return CURLE_OUT_OF_MEMORY;
01033 
01034 #ifdef ENABLE_IPV6
01035     if(*string_ftpport == '[') {
01036       /* [ipv6]:port(-range) */
01037       ip_start = string_ftpport + 1;
01038       ip_end = strchr(string_ftpport, ']');
01039       if(ip_end)
01040         strncpy(addr, ip_start, ip_end - ip_start);
01041     }
01042     else
01043 #endif
01044       if(*string_ftpport == ':') {
01045         /* :port */
01046         ip_end = string_ftpport;
01047       }
01048       else {
01049         ip_end = strchr(string_ftpport, ':');
01050         if(ip_end) {
01051           /* either ipv6 or (ipv4|domain|interface):port(-range) */
01052 #ifdef ENABLE_IPV6
01053           if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
01054             /* ipv6 */
01055             port_min = port_max = 0;
01056             strcpy(addr, string_ftpport);
01057             ip_end = NULL; /* this got no port ! */
01058           }
01059           else
01060 #endif
01061             /* (ipv4|domain|interface):port(-range) */
01062             strncpy(addr, string_ftpport, ip_end - ip_start);
01063         }
01064         else
01065           /* ipv4|interface */
01066           strcpy(addr, string_ftpport);
01067       }
01068 
01069     /* parse the port */
01070     if(ip_end != NULL) {
01071       port_start = strchr(ip_end, ':');
01072       if(port_start) {
01073         port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
01074         port_sep = strchr(port_start, '-');
01075         if(port_sep) {
01076           port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
01077         }
01078         else
01079           port_max = port_min;
01080       }
01081     }
01082 
01083     /* correct errors like:
01084      *  :1234-1230
01085      *  :-4711,  in this case port_min is (unsigned)-1,
01086      *           therefore port_min > port_max for all cases
01087      *           but port_max = (unsigned)-1
01088      */
01089     if(port_min > port_max)
01090       port_min = port_max = 0;
01091 
01092 
01093     if(*addr != '\0') {
01094       /* attempt to get the address of the given interface name */
01095       switch(Curl_if2ip(conn->ip_addr->ai_family,
01096                         Curl_ipv6_scope(conn->ip_addr->ai_addr),
01097                         conn->scope_id, addr, hbuf, sizeof(hbuf))) {
01098         case IF2IP_NOT_FOUND:
01099           /* not an interface, use the given string as host name instead */
01100           host = addr;
01101           break;
01102         case IF2IP_AF_NOT_SUPPORTED:
01103           return CURLE_FTP_PORT_FAILED;
01104         case IF2IP_FOUND:
01105           host = hbuf; /* use the hbuf for host name */
01106       }
01107     }
01108     else
01109       /* there was only a port(-range) given, default the host */
01110       host = NULL;
01111   } /* data->set.ftpport */
01112 
01113   if(!host) {
01114     /* not an interface and not a host name, get default by extracting
01115        the IP from the control connection */
01116 
01117     sslen = sizeof(ss);
01118     if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
01119       failf(data, "getsockname() failed: %s",
01120           Curl_strerror(conn, SOCKERRNO) );
01121       free(addr);
01122       return CURLE_FTP_PORT_FAILED;
01123     }
01124     switch(sa->sa_family) {
01125 #ifdef ENABLE_IPV6
01126     case AF_INET6:
01127       Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
01128       break;
01129 #endif
01130     default:
01131       Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
01132       break;
01133     }
01134     host = hbuf; /* use this host name */
01135     possibly_non_local = FALSE; /* we know it is local now */
01136   }
01137 
01138   /* resolv ip/host to ip */
01139   rc = Curl_resolv(conn, host, 0, &h);
01140   if(rc == CURLRESOLV_PENDING)
01141     (void)Curl_resolver_wait_resolv(conn, &h);
01142   if(h) {
01143     res = h->addr;
01144     /* when we return from this function, we can forget about this entry
01145        to we can unlock it now already */
01146     Curl_resolv_unlock(data, h);
01147   } /* (h) */
01148   else
01149     res = NULL; /* failure! */
01150 
01151   if(res == NULL) {
01152     failf(data, "failed to resolve the address provided to PORT: %s", host);
01153     free(addr);
01154     return CURLE_FTP_PORT_FAILED;
01155   }
01156 
01157   free(addr);
01158   host = NULL;
01159 
01160   /* step 2, create a socket for the requested address */
01161 
01162   portsock = CURL_SOCKET_BAD;
01163   error = 0;
01164   for(ai = res; ai; ai = ai->ai_next) {
01165     result = Curl_socket(conn, ai, NULL, &portsock);
01166     if(result) {
01167       error = SOCKERRNO;
01168       continue;
01169     }
01170     break;
01171   }
01172   if(!ai) {
01173     failf(data, "socket failure: %s", Curl_strerror(conn, error));
01174     return CURLE_FTP_PORT_FAILED;
01175   }
01176 
01177   /* step 3, bind to a suitable local address */
01178 
01179   memcpy(sa, ai->ai_addr, ai->ai_addrlen);
01180   sslen = ai->ai_addrlen;
01181 
01182   for(port = port_min; port <= port_max;) {
01183     if(sa->sa_family == AF_INET)
01184       sa4->sin_port = htons(port);
01185 #ifdef ENABLE_IPV6
01186     else
01187       sa6->sin6_port = htons(port);
01188 #endif
01189     /* Try binding the given address. */
01190     if(bind(portsock, sa, sslen) ) {
01191       /* It failed. */
01192       error = SOCKERRNO;
01193       if(possibly_non_local && (error == EADDRNOTAVAIL)) {
01194         /* The requested bind address is not local.  Use the address used for
01195          * the control connection instead and restart the port loop
01196          */
01197 
01198         infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
01199               Curl_strerror(conn, error) );
01200 
01201         sslen = sizeof(ss);
01202         if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
01203           failf(data, "getsockname() failed: %s",
01204                 Curl_strerror(conn, SOCKERRNO) );
01205           Curl_closesocket(conn, portsock);
01206           return CURLE_FTP_PORT_FAILED;
01207         }
01208         port = port_min;
01209         possibly_non_local = FALSE; /* don't try this again */
01210         continue;
01211       }
01212       else if(error != EADDRINUSE && error != EACCES) {
01213         failf(data, "bind(port=%hu) failed: %s", port,
01214               Curl_strerror(conn, error) );
01215         Curl_closesocket(conn, portsock);
01216         return CURLE_FTP_PORT_FAILED;
01217       }
01218     }
01219     else
01220       break;
01221 
01222     port++;
01223   }
01224 
01225   /* maybe all ports were in use already*/
01226   if(port > port_max) {
01227     failf(data, "bind() failed, we ran out of ports!");
01228     Curl_closesocket(conn, portsock);
01229     return CURLE_FTP_PORT_FAILED;
01230   }
01231 
01232   /* get the name again after the bind() so that we can extract the
01233      port number it uses now */
01234   sslen = sizeof(ss);
01235   if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
01236     failf(data, "getsockname() failed: %s",
01237           Curl_strerror(conn, SOCKERRNO) );
01238     Curl_closesocket(conn, portsock);
01239     return CURLE_FTP_PORT_FAILED;
01240   }
01241 
01242   /* step 4, listen on the socket */
01243 
01244   if(listen(portsock, 1)) {
01245     failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
01246     Curl_closesocket(conn, portsock);
01247     return CURLE_FTP_PORT_FAILED;
01248   }
01249 
01250   /* step 5, send the proper FTP command */
01251 
01252   /* get a plain printable version of the numerical address to work with
01253      below */
01254   Curl_printable_address(ai, myhost, sizeof(myhost));
01255 
01256 #ifdef ENABLE_IPV6
01257   if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
01258     /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
01259        request and enable EPRT again! */
01260     conn->bits.ftp_use_eprt = TRUE;
01261 #endif
01262 
01263   for(; fcmd != DONE; fcmd++) {
01264 
01265     if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
01266       /* if disabled, goto next */
01267       continue;
01268 
01269     if((PORT == fcmd) && sa->sa_family != AF_INET)
01270       /* PORT is IPv4 only */
01271       continue;
01272 
01273     switch(sa->sa_family) {
01274     case AF_INET:
01275       port = ntohs(sa4->sin_port);
01276       break;
01277 #ifdef ENABLE_IPV6
01278     case AF_INET6:
01279       port = ntohs(sa6->sin6_port);
01280       break;
01281 #endif
01282     default:
01283       continue; /* might as well skip this */
01284     }
01285 
01286     if(EPRT == fcmd) {
01287       /*
01288        * Two fine examples from RFC2428;
01289        *
01290        * EPRT |1|132.235.1.2|6275|
01291        *
01292        * EPRT |2|1080::8:800:200C:417A|5282|
01293        */
01294 
01295       result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
01296                              sa->sa_family == AF_INET?1:2,
01297                              myhost, port);
01298       if(result) {
01299         failf(data, "Failure sending EPRT command: %s",
01300               curl_easy_strerror(result));
01301         Curl_closesocket(conn, portsock);
01302         /* don't retry using PORT */
01303         ftpc->count1 = PORT;
01304         /* bail out */
01305         state(conn, FTP_STOP);
01306         return result;
01307       }
01308       break;
01309     }
01310     else if(PORT == fcmd) {
01311       char *source = myhost;
01312       char *dest = tmp;
01313 
01314       /* translate x.x.x.x to x,x,x,x */
01315       while(source && *source) {
01316         if(*source == '.')
01317           *dest=',';
01318         else
01319           *dest = *source;
01320         dest++;
01321         source++;
01322       }
01323       *dest = 0;
01324       snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
01325 
01326       result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
01327       if(result) {
01328         failf(data, "Failure sending PORT command: %s",
01329               curl_easy_strerror(result));
01330         Curl_closesocket(conn, portsock);
01331         /* bail out */
01332         state(conn, FTP_STOP);
01333         return result;
01334       }
01335       break;
01336     }
01337   }
01338 
01339   /* store which command was sent */
01340   ftpc->count1 = fcmd;
01341 
01342   close_secondarysocket(conn);
01343 
01344   /* we set the secondary socket variable to this for now, it is only so that
01345      the cleanup function will close it in case we fail before the true
01346      secondary stuff is made */
01347   conn->sock[SECONDARYSOCKET] = portsock;
01348 
01349   /* this tcpconnect assignment below is a hackish work-around to make the
01350      multi interface with active FTP work - as it will not wait for a
01351      (passive) connect in Curl_is_connected().
01352 
01353      The *proper* fix is to make sure that the active connection from the
01354      server is done in a non-blocking way. Currently, it is still BLOCKING.
01355   */
01356   conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
01357 
01358   state(conn, FTP_PORT);
01359   return result;
01360 }
01361 
01362 static CURLcode ftp_state_use_pasv(struct connectdata *conn)
01363 {
01364   struct ftp_conn *ftpc = &conn->proto.ftpc;
01365   CURLcode result = CURLE_OK;
01366   /*
01367     Here's the excecutive summary on what to do:
01368 
01369     PASV is RFC959, expect:
01370     227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
01371 
01372     LPSV is RFC1639, expect:
01373     228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
01374 
01375     EPSV is RFC2428, expect:
01376     229 Entering Extended Passive Mode (|||port|)
01377 
01378   */
01379 
01380   static const char mode[][5] = { "EPSV", "PASV" };
01381   int modeoff;
01382 
01383 #ifdef PF_INET6
01384   if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
01385     /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
01386        request and enable EPSV again! */
01387     conn->bits.ftp_use_epsv = TRUE;
01388 #endif
01389 
01390   modeoff = conn->bits.ftp_use_epsv?0:1;
01391 
01392   PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
01393 
01394   ftpc->count1 = modeoff;
01395   state(conn, FTP_PASV);
01396   infof(conn->data, "Connect data stream passively\n");
01397 
01398   return result;
01399 }
01400 
01401 /*
01402  * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
01403  *
01404  * REST is the last command in the chain of commands when a "head"-like
01405  * request is made. Thus, if an actual transfer is to be made this is where we
01406  * take off for real.
01407  */
01408 static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
01409 {
01410   CURLcode result = CURLE_OK;
01411   struct FTP *ftp = conn->data->req.protop;
01412   struct Curl_easy *data = conn->data;
01413 
01414   if(ftp->transfer != FTPTRANSFER_BODY) {
01415     /* doesn't transfer any data */
01416 
01417     /* still possibly do PRE QUOTE jobs */
01418     state(conn, FTP_RETR_PREQUOTE);
01419     result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
01420   }
01421   else if(data->set.ftp_use_port) {
01422     /* We have chosen to use the PORT (or similar) command */
01423     result = ftp_state_use_port(conn, EPRT);
01424   }
01425   else {
01426     /* We have chosen (this is default) to use the PASV (or similar) command */
01427     if(data->set.ftp_use_pret) {
01428       /* The user has requested that we send a PRET command
01429          to prepare the server for the upcoming PASV */
01430       if(!conn->proto.ftpc.file) {
01431         PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
01432                 data->set.str[STRING_CUSTOMREQUEST]?
01433                 data->set.str[STRING_CUSTOMREQUEST]:
01434                 (data->set.ftp_list_only?"NLST":"LIST"));
01435       }
01436       else if(data->set.upload) {
01437         PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
01438       }
01439       else {
01440         PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
01441       }
01442       state(conn, FTP_PRET);
01443     }
01444     else {
01445       result = ftp_state_use_pasv(conn);
01446     }
01447   }
01448   return result;
01449 }
01450 
01451 static CURLcode ftp_state_rest(struct connectdata *conn)
01452 {
01453   CURLcode result = CURLE_OK;
01454   struct FTP *ftp = conn->data->req.protop;
01455   struct ftp_conn *ftpc = &conn->proto.ftpc;
01456 
01457   if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
01458     /* if a "head"-like request is being made (on a file) */
01459 
01460     /* Determine if server can respond to REST command and therefore
01461        whether it supports range */
01462     PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
01463 
01464     state(conn, FTP_REST);
01465   }
01466   else
01467     result = ftp_state_prepare_transfer(conn);
01468 
01469   return result;
01470 }
01471 
01472 static CURLcode ftp_state_size(struct connectdata *conn)
01473 {
01474   CURLcode result = CURLE_OK;
01475   struct FTP *ftp = conn->data->req.protop;
01476   struct ftp_conn *ftpc = &conn->proto.ftpc;
01477 
01478   if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
01479     /* if a "head"-like request is being made (on a file) */
01480 
01481     /* we know ftpc->file is a valid pointer to a file name */
01482     PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
01483 
01484     state(conn, FTP_SIZE);
01485   }
01486   else
01487     result = ftp_state_rest(conn);
01488 
01489   return result;
01490 }
01491 
01492 static CURLcode ftp_state_list(struct connectdata *conn)
01493 {
01494   CURLcode result = CURLE_OK;
01495   struct Curl_easy *data = conn->data;
01496 
01497   /* If this output is to be machine-parsed, the NLST command might be better
01498      to use, since the LIST command output is not specified or standard in any
01499      way. It has turned out that the NLST list output is not the same on all
01500      servers either... */
01501 
01502   /*
01503      if FTPFILE_NOCWD was specified, we are currently in
01504      the user's home directory, so we should add the path
01505      as argument for the LIST / NLST / or custom command.
01506      Whether the server will support this, is uncertain.
01507 
01508      The other ftp_filemethods will CWD into dir/dir/ first and
01509      then just do LIST (in that case: nothing to do here)
01510   */
01511   char *cmd, *lstArg, *slashPos;
01512 
01513   lstArg = NULL;
01514   if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
01515      data->state.path &&
01516      data->state.path[0] &&
01517      strchr(data->state.path, '/')) {
01518 
01519     lstArg = strdup(data->state.path);
01520     if(!lstArg)
01521       return CURLE_OUT_OF_MEMORY;
01522 
01523     /* Check if path does not end with /, as then we cut off the file part */
01524     if(lstArg[strlen(lstArg) - 1] != '/')  {
01525 
01526       /* chop off the file part if format is dir/dir/file */
01527       slashPos = strrchr(lstArg, '/');
01528       if(slashPos)
01529         *(slashPos+1) = '\0';
01530     }
01531   }
01532 
01533   cmd = aprintf("%s%s%s",
01534                 data->set.str[STRING_CUSTOMREQUEST]?
01535                 data->set.str[STRING_CUSTOMREQUEST]:
01536                 (data->set.ftp_list_only?"NLST":"LIST"),
01537                 lstArg? " ": "",
01538                 lstArg? lstArg: "");
01539 
01540   if(!cmd) {
01541     free(lstArg);
01542     return CURLE_OUT_OF_MEMORY;
01543   }
01544 
01545   result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
01546 
01547   free(lstArg);
01548   free(cmd);
01549 
01550   if(result)
01551     return result;
01552 
01553   state(conn, FTP_LIST);
01554 
01555   return result;
01556 }
01557 
01558 static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
01559 {
01560   CURLcode result = CURLE_OK;
01561 
01562   /* We've sent the TYPE, now we must send the list of prequote strings */
01563 
01564   result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
01565 
01566   return result;
01567 }
01568 
01569 static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
01570 {
01571   CURLcode result = CURLE_OK;
01572 
01573   /* We've sent the TYPE, now we must send the list of prequote strings */
01574 
01575   result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
01576 
01577   return result;
01578 }
01579 
01580 static CURLcode ftp_state_type(struct connectdata *conn)
01581 {
01582   CURLcode result = CURLE_OK;
01583   struct FTP *ftp = conn->data->req.protop;
01584   struct Curl_easy *data = conn->data;
01585   struct ftp_conn *ftpc = &conn->proto.ftpc;
01586 
01587   /* If we have selected NOBODY and HEADER, it means that we only want file
01588      information. Which in FTP can't be much more than the file size and
01589      date. */
01590   if(data->set.opt_no_body && ftpc->file &&
01591      ftp_need_type(conn, data->set.prefer_ascii)) {
01592     /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
01593        may not support it! It is however the only way we have to get a file's
01594        size! */
01595 
01596     ftp->transfer = FTPTRANSFER_INFO;
01597     /* this means no actual transfer will be made */
01598 
01599     /* Some servers return different sizes for different modes, and thus we
01600        must set the proper type before we check the size */
01601     result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
01602     if(result)
01603       return result;
01604   }
01605   else
01606     result = ftp_state_size(conn);
01607 
01608   return result;
01609 }
01610 
01611 /* This is called after the CWD commands have been done in the beginning of
01612    the DO phase */
01613 static CURLcode ftp_state_mdtm(struct connectdata *conn)
01614 {
01615   CURLcode result = CURLE_OK;
01616   struct Curl_easy *data = conn->data;
01617   struct ftp_conn *ftpc = &conn->proto.ftpc;
01618 
01619   /* Requested time of file or time-depended transfer? */
01620   if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
01621 
01622     /* we have requested to get the modified-time of the file, this is a white
01623        spot as the MDTM is not mentioned in RFC959 */
01624     PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
01625 
01626     state(conn, FTP_MDTM);
01627   }
01628   else
01629     result = ftp_state_type(conn);
01630 
01631   return result;
01632 }
01633 
01634 
01635 /* This is called after the TYPE and possible quote commands have been sent */
01636 static CURLcode ftp_state_ul_setup(struct connectdata *conn,
01637                                    bool sizechecked)
01638 {
01639   CURLcode result = CURLE_OK;
01640   struct FTP *ftp = conn->data->req.protop;
01641   struct Curl_easy *data = conn->data;
01642   struct ftp_conn *ftpc = &conn->proto.ftpc;
01643   int seekerr = CURL_SEEKFUNC_OK;
01644 
01645   if((data->state.resume_from && !sizechecked) ||
01646      ((data->state.resume_from > 0) && sizechecked)) {
01647     /* we're about to continue the uploading of a file */
01648     /* 1. get already existing file's size. We use the SIZE command for this
01649        which may not exist in the server!  The SIZE command is not in
01650        RFC959. */
01651 
01652     /* 2. This used to set REST. But since we can do append, we
01653        don't another ftp command. We just skip the source file
01654        offset and then we APPEND the rest on the file instead */
01655 
01656     /* 3. pass file-size number of bytes in the source file */
01657     /* 4. lower the infilesize counter */
01658     /* => transfer as usual */
01659 
01660     if(data->state.resume_from < 0) {
01661       /* Got no given size to start from, figure it out */
01662       PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
01663       state(conn, FTP_STOR_SIZE);
01664       return result;
01665     }
01666 
01667     /* enable append */
01668     data->set.ftp_append = TRUE;
01669 
01670     /* Let's read off the proper amount of bytes from the input. */
01671     if(conn->seek_func) {
01672       seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
01673                                 SEEK_SET);
01674     }
01675 
01676     if(seekerr != CURL_SEEKFUNC_OK) {
01677       if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
01678         failf(data, "Could not seek stream");
01679         return CURLE_FTP_COULDNT_USE_REST;
01680       }
01681       /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
01682       else {
01683         curl_off_t passed=0;
01684         do {
01685           size_t readthisamountnow =
01686             (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
01687             BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
01688 
01689           size_t actuallyread =
01690             data->state.fread_func(data->state.buffer, 1, readthisamountnow,
01691                                    data->state.in);
01692 
01693           passed += actuallyread;
01694           if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
01695             /* this checks for greater-than only to make sure that the
01696                CURL_READFUNC_ABORT return code still aborts */
01697             failf(data, "Failed to read data");
01698             return CURLE_FTP_COULDNT_USE_REST;
01699           }
01700         } while(passed < data->state.resume_from);
01701       }
01702     }
01703     /* now, decrease the size of the read */
01704     if(data->state.infilesize>0) {
01705       data->state.infilesize -= data->state.resume_from;
01706 
01707       if(data->state.infilesize <= 0) {
01708         infof(data, "File already completely uploaded\n");
01709 
01710         /* no data to transfer */
01711         Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01712 
01713         /* Set ->transfer so that we won't get any error in
01714          * ftp_done() because we didn't transfer anything! */
01715         ftp->transfer = FTPTRANSFER_NONE;
01716 
01717         state(conn, FTP_STOP);
01718         return CURLE_OK;
01719       }
01720     }
01721     /* we've passed, proceed as normal */
01722   } /* resume_from */
01723 
01724   PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
01725           ftpc->file);
01726 
01727   state(conn, FTP_STOR);
01728 
01729   return result;
01730 }
01731 
01732 static CURLcode ftp_state_quote(struct connectdata *conn,
01733                                 bool init,
01734                                 ftpstate instate)
01735 {
01736   CURLcode result = CURLE_OK;
01737   struct Curl_easy *data = conn->data;
01738   struct FTP *ftp = data->req.protop;
01739   struct ftp_conn *ftpc = &conn->proto.ftpc;
01740   bool quote=FALSE;
01741   struct curl_slist *item;
01742 
01743   switch(instate) {
01744   case FTP_QUOTE:
01745   default:
01746     item = data->set.quote;
01747     break;
01748   case FTP_RETR_PREQUOTE:
01749   case FTP_STOR_PREQUOTE:
01750     item = data->set.prequote;
01751     break;
01752   case FTP_POSTQUOTE:
01753     item = data->set.postquote;
01754     break;
01755   }
01756 
01757   /*
01758    * This state uses:
01759    * 'count1' to iterate over the commands to send
01760    * 'count2' to store wether to allow commands to fail
01761    */
01762 
01763   if(init)
01764     ftpc->count1 = 0;
01765   else
01766     ftpc->count1++;
01767 
01768   if(item) {
01769     int i = 0;
01770 
01771     /* Skip count1 items in the linked list */
01772     while((i< ftpc->count1) && item) {
01773       item = item->next;
01774       i++;
01775     }
01776     if(item) {
01777       char *cmd = item->data;
01778       if(cmd[0] == '*') {
01779         cmd++;
01780         ftpc->count2 = 1; /* the sent command is allowed to fail */
01781       }
01782       else
01783         ftpc->count2 = 0; /* failure means cancel operation */
01784 
01785       PPSENDF(&ftpc->pp, "%s", cmd);
01786       state(conn, instate);
01787       quote = TRUE;
01788     }
01789   }
01790 
01791   if(!quote) {
01792     /* No more quote to send, continue to ... */
01793     switch(instate) {
01794     case FTP_QUOTE:
01795     default:
01796       result = ftp_state_cwd(conn);
01797       break;
01798     case FTP_RETR_PREQUOTE:
01799       if(ftp->transfer != FTPTRANSFER_BODY)
01800         state(conn, FTP_STOP);
01801       else {
01802         if(ftpc->known_filesize != -1) {
01803           Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
01804           result = ftp_state_retr(conn, ftpc->known_filesize);
01805         }
01806         else {
01807           if(data->set.ignorecl) {
01808             /* This code is to support download of growing files.  It prevents
01809                the state machine from requesting the file size from the
01810                server.  With an unknown file size the download continues until
01811                the server terminates it, otherwise the client stops if the
01812                received byte count exceeds the reported file size.  Set option
01813                CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
01814             PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
01815             state(conn, FTP_RETR);
01816           }
01817           else {
01818             PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
01819             state(conn, FTP_RETR_SIZE);
01820           }
01821         }
01822       }
01823       break;
01824     case FTP_STOR_PREQUOTE:
01825       result = ftp_state_ul_setup(conn, FALSE);
01826       break;
01827     case FTP_POSTQUOTE:
01828       break;
01829     }
01830   }
01831 
01832   return result;
01833 }
01834 
01835 /* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
01836    problems */
01837 static CURLcode ftp_epsv_disable(struct connectdata *conn)
01838 {
01839   CURLcode result = CURLE_OK;
01840 
01841   if(conn->bits.ipv6) {
01842     /* We can't disable EPSV when doing IPv6, so this is instead a fail */
01843     failf(conn->data, "Failed EPSV attempt, exiting\n");
01844     return CURLE_WEIRD_SERVER_REPLY;
01845   }
01846 
01847   infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
01848   /* disable it for next transfer */
01849   conn->bits.ftp_use_epsv = FALSE;
01850   conn->data->state.errorbuf = FALSE; /* allow error message to get
01851                                          rewritten */
01852   PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
01853   conn->proto.ftpc.count1++;
01854   /* remain in/go to the FTP_PASV state */
01855   state(conn, FTP_PASV);
01856   return result;
01857 }
01858 
01859 
01860 static char *control_address(struct connectdata *conn)
01861 {
01862   /* Returns the control connection IP address.
01863      If a proxy tunnel is used, returns the original host name instead, because
01864      the effective control connection address is the proxy address,
01865      not the ftp host. */
01866   if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
01867     return conn->host.name;
01868 
01869   return conn->ip_addr_str;
01870 }
01871 
01872 static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
01873                                     int ftpcode)
01874 {
01875   struct ftp_conn *ftpc = &conn->proto.ftpc;
01876   CURLcode result;
01877   struct Curl_easy *data=conn->data;
01878   struct Curl_dns_entry *addr=NULL;
01879   int rc;
01880   unsigned short connectport; /* the local port connect() should use! */
01881   char *str=&data->state.buffer[4];  /* start on the first letter */
01882 
01883   /* if we come here again, make sure the former name is cleared */
01884   Curl_safefree(ftpc->newhost);
01885 
01886   if((ftpc->count1 == 0) &&
01887      (ftpcode == 229)) {
01888     /* positive EPSV response */
01889     char *ptr = strchr(str, '(');
01890     if(ptr) {
01891       unsigned int num;
01892       char separator[4];
01893       ptr++;
01894       if(5 == sscanf(ptr, "%c%c%c%u%c",
01895                      &separator[0],
01896                      &separator[1],
01897                      &separator[2],
01898                      &num,
01899                      &separator[3])) {
01900         const char sep1 = separator[0];
01901         int i;
01902 
01903         /* The four separators should be identical, or else this is an oddly
01904            formatted reply and we bail out immediately. */
01905         for(i=1; i<4; i++) {
01906           if(separator[i] != sep1) {
01907             ptr=NULL; /* set to NULL to signal error */
01908             break;
01909           }
01910         }
01911         if(num > 0xffff) {
01912           failf(data, "Illegal port number in EPSV reply");
01913           return CURLE_FTP_WEIRD_PASV_REPLY;
01914         }
01915         if(ptr) {
01916           ftpc->newport = (unsigned short)(num & 0xffff);
01917           ftpc->newhost = strdup(control_address(conn));
01918           if(!ftpc->newhost)
01919             return CURLE_OUT_OF_MEMORY;
01920         }
01921       }
01922       else
01923         ptr=NULL;
01924     }
01925     if(!ptr) {
01926       failf(data, "Weirdly formatted EPSV reply");
01927       return CURLE_FTP_WEIRD_PASV_REPLY;
01928     }
01929   }
01930   else if((ftpc->count1 == 1) &&
01931           (ftpcode == 227)) {
01932     /* positive PASV response */
01933     int ip[4];
01934     int port[2];
01935 
01936     /*
01937      * Scan for a sequence of six comma-separated numbers and use them as
01938      * IP+port indicators.
01939      *
01940      * Found reply-strings include:
01941      * "227 Entering Passive Mode (127,0,0,1,4,51)"
01942      * "227 Data transfer will passively listen to 127,0,0,1,4,51"
01943      * "227 Entering passive mode. 127,0,0,1,4,51"
01944      */
01945     while(*str) {
01946       if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
01947                      &ip[0], &ip[1], &ip[2], &ip[3],
01948                      &port[0], &port[1]))
01949         break;
01950       str++;
01951     }
01952 
01953     if(!*str) {
01954       failf(data, "Couldn't interpret the 227-response");
01955       return CURLE_FTP_WEIRD_227_FORMAT;
01956     }
01957 
01958     /* we got OK from server */
01959     if(data->set.ftp_skip_ip) {
01960       /* told to ignore the remotely given IP but instead use the host we used
01961          for the control connection */
01962       infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
01963             ip[0], ip[1], ip[2], ip[3],
01964             conn->host.name);
01965       ftpc->newhost = strdup(control_address(conn));
01966     }
01967     else
01968       ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
01969 
01970     if(!ftpc->newhost)
01971       return CURLE_OUT_OF_MEMORY;
01972 
01973     ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
01974   }
01975   else if(ftpc->count1 == 0) {
01976     /* EPSV failed, move on to PASV */
01977     return ftp_epsv_disable(conn);
01978   }
01979   else {
01980     failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
01981     return CURLE_FTP_WEIRD_PASV_REPLY;
01982   }
01983 
01984   if(conn->bits.proxy) {
01985     /*
01986      * This connection uses a proxy and we need to connect to the proxy again
01987      * here. We don't want to rely on a former host lookup that might've
01988      * expired now, instead we remake the lookup here and now!
01989      */
01990     const char * const host_name = conn->bits.socksproxy ?
01991       conn->socks_proxy.host.name : conn->http_proxy.host.name;
01992     rc = Curl_resolv(conn, host_name, (int)conn->port, &addr);
01993     if(rc == CURLRESOLV_PENDING)
01994       /* BLOCKING, ignores the return code but 'addr' will be NULL in
01995          case of failure */
01996       (void)Curl_resolver_wait_resolv(conn, &addr);
01997 
01998     connectport =
01999       (unsigned short)conn->port; /* we connect to the proxy's port */
02000 
02001     if(!addr) {
02002       failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
02003       return CURLE_FTP_CANT_GET_HOST;
02004     }
02005   }
02006   else {
02007     /* normal, direct, ftp connection */
02008     rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
02009     if(rc == CURLRESOLV_PENDING)
02010       /* BLOCKING */
02011       (void)Curl_resolver_wait_resolv(conn, &addr);
02012 
02013     connectport = ftpc->newport; /* we connect to the remote port */
02014 
02015     if(!addr) {
02016       failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
02017       return CURLE_FTP_CANT_GET_HOST;
02018     }
02019   }
02020 
02021   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
02022   result = Curl_connecthost(conn, addr);
02023 
02024   if(result) {
02025     Curl_resolv_unlock(data, addr); /* we're done using this address */
02026     if(ftpc->count1 == 0 && ftpcode == 229)
02027       return ftp_epsv_disable(conn);
02028 
02029     return result;
02030   }
02031 
02032 
02033   /*
02034    * When this is used from the multi interface, this might've returned with
02035    * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
02036    * connect to connect.
02037    */
02038 
02039   if(data->set.verbose)
02040     /* this just dumps information about this second connection */
02041     ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
02042 
02043   Curl_safefree(conn->secondaryhostname);
02044   conn->secondaryhostname = strdup(ftpc->newhost);
02045   conn->secondary_port = ftpc->newport;
02046 
02047   Curl_resolv_unlock(data, addr); /* we're done using this address */
02048   conn->bits.do_more = TRUE;
02049   state(conn, FTP_STOP); /* this phase is completed */
02050 
02051   return result;
02052 }
02053 
02054 static CURLcode ftp_state_port_resp(struct connectdata *conn,
02055                                     int ftpcode)
02056 {
02057   struct Curl_easy *data = conn->data;
02058   struct ftp_conn *ftpc = &conn->proto.ftpc;
02059   ftpport fcmd = (ftpport)ftpc->count1;
02060   CURLcode result = CURLE_OK;
02061 
02062   /* The FTP spec tells a positive response should have code 200.
02063      Be more permissive here to tolerate deviant servers. */
02064   if(ftpcode / 100 != 2) {
02065     /* the command failed */
02066 
02067     if(EPRT == fcmd) {
02068       infof(data, "disabling EPRT usage\n");
02069       conn->bits.ftp_use_eprt = FALSE;
02070     }
02071     fcmd++;
02072 
02073     if(fcmd == DONE) {
02074       failf(data, "Failed to do PORT");
02075       result = CURLE_FTP_PORT_FAILED;
02076     }
02077     else
02078       /* try next */
02079       result = ftp_state_use_port(conn, fcmd);
02080   }
02081   else {
02082     infof(data, "Connect data stream actively\n");
02083     state(conn, FTP_STOP); /* end of DO phase */
02084     result = ftp_dophase_done(conn, FALSE);
02085   }
02086 
02087   return result;
02088 }
02089 
02090 static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
02091                                     int ftpcode)
02092 {
02093   CURLcode result = CURLE_OK;
02094   struct Curl_easy *data=conn->data;
02095   struct FTP *ftp = data->req.protop;
02096   struct ftp_conn *ftpc = &conn->proto.ftpc;
02097 
02098   switch(ftpcode) {
02099   case 213:
02100     {
02101       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
02102          last .sss part is optional and means fractions of a second */
02103       int year, month, day, hour, minute, second;
02104       char *buf = data->state.buffer;
02105       if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
02106                      &year, &month, &day, &hour, &minute, &second)) {
02107         /* we have a time, reformat it */
02108         time_t secs=time(NULL);
02109         /* using the good old yacc/bison yuck */
02110         snprintf(buf, sizeof(conn->data->state.buffer),
02111                  "%04d%02d%02d %02d:%02d:%02d GMT",
02112                  year, month, day, hour, minute, second);
02113         /* now, convert this into a time() value: */
02114         data->info.filetime = (long)curl_getdate(buf, &secs);
02115       }
02116 
02117 #ifdef CURL_FTP_HTTPSTYLE_HEAD
02118       /* If we asked for a time of the file and we actually got one as well,
02119          we "emulate" a HTTP-style header in our output. */
02120 
02121       if(data->set.opt_no_body &&
02122          ftpc->file &&
02123          data->set.get_filetime &&
02124          (data->info.filetime>=0) ) {
02125         time_t filetime = (time_t)data->info.filetime;
02126         struct tm buffer;
02127         const struct tm *tm = &buffer;
02128 
02129         result = Curl_gmtime(filetime, &buffer);
02130         if(result)
02131           return result;
02132 
02133         /* format: "Tue, 15 Nov 1994 12:45:26" */
02134         snprintf(buf, BUFSIZE-1,
02135                  "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
02136                  Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
02137                  tm->tm_mday,
02138                  Curl_month[tm->tm_mon],
02139                  tm->tm_year + 1900,
02140                  tm->tm_hour,
02141                  tm->tm_min,
02142                  tm->tm_sec);
02143         result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
02144         if(result)
02145           return result;
02146       } /* end of a ridiculous amount of conditionals */
02147 #endif
02148     }
02149     break;
02150   default:
02151     infof(data, "unsupported MDTM reply format\n");
02152     break;
02153   case 550: /* "No such file or directory" */
02154     failf(data, "Given file does not exist");
02155     result = CURLE_FTP_COULDNT_RETR_FILE;
02156     break;
02157   }
02158 
02159   if(data->set.timecondition) {
02160     if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
02161       switch(data->set.timecondition) {
02162       case CURL_TIMECOND_IFMODSINCE:
02163       default:
02164         if(data->info.filetime <= data->set.timevalue) {
02165           infof(data, "The requested document is not new enough\n");
02166           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
02167           data->info.timecond = TRUE;
02168           state(conn, FTP_STOP);
02169           return CURLE_OK;
02170         }
02171         break;
02172       case CURL_TIMECOND_IFUNMODSINCE:
02173         if(data->info.filetime > data->set.timevalue) {
02174           infof(data, "The requested document is not old enough\n");
02175           ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
02176           data->info.timecond = TRUE;
02177           state(conn, FTP_STOP);
02178           return CURLE_OK;
02179         }
02180         break;
02181       } /* switch */
02182     }
02183     else {
02184       infof(data, "Skipping time comparison\n");
02185     }
02186   }
02187 
02188   if(!result)
02189     result = ftp_state_type(conn);
02190 
02191   return result;
02192 }
02193 
02194 static CURLcode ftp_state_type_resp(struct connectdata *conn,
02195                                     int ftpcode,
02196                                     ftpstate instate)
02197 {
02198   CURLcode result = CURLE_OK;
02199   struct Curl_easy *data=conn->data;
02200 
02201   if(ftpcode/100 != 2) {
02202     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
02203        successful 'TYPE I'. While that is not as RFC959 says, it is still a
02204        positive response code and we allow that. */
02205     failf(data, "Couldn't set desired mode");
02206     return CURLE_FTP_COULDNT_SET_TYPE;
02207   }
02208   if(ftpcode != 200)
02209     infof(data, "Got a %03d response code instead of the assumed 200\n",
02210           ftpcode);
02211 
02212   if(instate == FTP_TYPE)
02213     result = ftp_state_size(conn);
02214   else if(instate == FTP_LIST_TYPE)
02215     result = ftp_state_list(conn);
02216   else if(instate == FTP_RETR_TYPE)
02217     result = ftp_state_retr_prequote(conn);
02218   else if(instate == FTP_STOR_TYPE)
02219     result = ftp_state_stor_prequote(conn);
02220 
02221   return result;
02222 }
02223 
02224 static CURLcode ftp_state_retr(struct connectdata *conn,
02225                                          curl_off_t filesize)
02226 {
02227   CURLcode result = CURLE_OK;
02228   struct Curl_easy *data=conn->data;
02229   struct FTP *ftp = data->req.protop;
02230   struct ftp_conn *ftpc = &conn->proto.ftpc;
02231 
02232   if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
02233     failf(data, "Maximum file size exceeded");
02234     return CURLE_FILESIZE_EXCEEDED;
02235   }
02236   ftp->downloadsize = filesize;
02237 
02238   if(data->state.resume_from) {
02239     /* We always (attempt to) get the size of downloads, so it is done before
02240        this even when not doing resumes. */
02241     if(filesize == -1) {
02242       infof(data, "ftp server doesn't support SIZE\n");
02243       /* We couldn't get the size and therefore we can't know if there really
02244          is a part of the file left to get, although the server will just
02245          close the connection when we start the connection so it won't cause
02246          us any harm, just not make us exit as nicely. */
02247     }
02248     else {
02249       /* We got a file size report, so we check that there actually is a
02250          part of the file left to get, or else we go home.  */
02251       if(data->state.resume_from< 0) {
02252         /* We're supposed to download the last abs(from) bytes */
02253         if(filesize < -data->state.resume_from) {
02254           failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
02255                 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
02256                 data->state.resume_from, filesize);
02257           return CURLE_BAD_DOWNLOAD_RESUME;
02258         }
02259         /* convert to size to download */
02260         ftp->downloadsize = -data->state.resume_from;
02261         /* download from where? */
02262         data->state.resume_from = filesize - ftp->downloadsize;
02263       }
02264       else {
02265         if(filesize < data->state.resume_from) {
02266           failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
02267                 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
02268                 data->state.resume_from, filesize);
02269           return CURLE_BAD_DOWNLOAD_RESUME;
02270         }
02271         /* Now store the number of bytes we are expected to download */
02272         ftp->downloadsize = filesize-data->state.resume_from;
02273       }
02274     }
02275 
02276     if(ftp->downloadsize == 0) {
02277       /* no data to transfer */
02278       Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
02279       infof(data, "File already completely downloaded\n");
02280 
02281       /* Set ->transfer so that we won't get any error in ftp_done()
02282        * because we didn't transfer the any file */
02283       ftp->transfer = FTPTRANSFER_NONE;
02284       state(conn, FTP_STOP);
02285       return CURLE_OK;
02286     }
02287 
02288     /* Set resume file transfer offset */
02289     infof(data, "Instructs server to resume from offset %"
02290           CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
02291 
02292     PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
02293             data->state.resume_from);
02294 
02295     state(conn, FTP_RETR_REST);
02296   }
02297   else {
02298     /* no resume */
02299     PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
02300     state(conn, FTP_RETR);
02301   }
02302 
02303   return result;
02304 }
02305 
02306 static CURLcode ftp_state_size_resp(struct connectdata *conn,
02307                                     int ftpcode,
02308                                     ftpstate instate)
02309 {
02310   CURLcode result = CURLE_OK;
02311   struct Curl_easy *data=conn->data;
02312   curl_off_t filesize;
02313   char *buf = data->state.buffer;
02314 
02315   /* get the size from the ascii string: */
02316   filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
02317 
02318   if(instate == FTP_SIZE) {
02319 #ifdef CURL_FTP_HTTPSTYLE_HEAD
02320     if(-1 != filesize) {
02321       snprintf(buf, sizeof(data->state.buffer),
02322                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
02323       result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
02324       if(result)
02325         return result;
02326     }
02327 #endif
02328     Curl_pgrsSetDownloadSize(data, filesize);
02329     result = ftp_state_rest(conn);
02330   }
02331   else if(instate == FTP_RETR_SIZE) {
02332     Curl_pgrsSetDownloadSize(data, filesize);
02333     result = ftp_state_retr(conn, filesize);
02334   }
02335   else if(instate == FTP_STOR_SIZE) {
02336     data->state.resume_from = filesize;
02337     result = ftp_state_ul_setup(conn, TRUE);
02338   }
02339 
02340   return result;
02341 }
02342 
02343 static CURLcode ftp_state_rest_resp(struct connectdata *conn,
02344                                     int ftpcode,
02345                                     ftpstate instate)
02346 {
02347   CURLcode result = CURLE_OK;
02348   struct ftp_conn *ftpc = &conn->proto.ftpc;
02349 
02350   switch(instate) {
02351   case FTP_REST:
02352   default:
02353 #ifdef CURL_FTP_HTTPSTYLE_HEAD
02354     if(ftpcode == 350) {
02355       char buffer[24]= { "Accept-ranges: bytes\r\n" };
02356       result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
02357       if(result)
02358         return result;
02359     }
02360 #endif
02361     result = ftp_state_prepare_transfer(conn);
02362     break;
02363 
02364   case FTP_RETR_REST:
02365     if(ftpcode != 350) {
02366       failf(conn->data, "Couldn't use REST");
02367       result = CURLE_FTP_COULDNT_USE_REST;
02368     }
02369     else {
02370       PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
02371       state(conn, FTP_RETR);
02372     }
02373     break;
02374   }
02375 
02376   return result;
02377 }
02378 
02379 static CURLcode ftp_state_stor_resp(struct connectdata *conn,
02380                                     int ftpcode, ftpstate instate)
02381 {
02382   CURLcode result = CURLE_OK;
02383   struct Curl_easy *data = conn->data;
02384 
02385   if(ftpcode>=400) {
02386     failf(data, "Failed FTP upload: %0d", ftpcode);
02387     state(conn, FTP_STOP);
02388     /* oops, we never close the sockets! */
02389     return CURLE_UPLOAD_FAILED;
02390   }
02391 
02392   conn->proto.ftpc.state_saved = instate;
02393 
02394   /* PORT means we are now awaiting the server to connect to us. */
02395   if(data->set.ftp_use_port) {
02396     bool connected;
02397 
02398     state(conn, FTP_STOP); /* no longer in STOR state */
02399 
02400     result = AllowServerConnect(conn, &connected);
02401     if(result)
02402       return result;
02403 
02404     if(!connected) {
02405       struct ftp_conn *ftpc = &conn->proto.ftpc;
02406       infof(data, "Data conn was not available immediately\n");
02407       ftpc->wait_data_conn = TRUE;
02408     }
02409 
02410     return CURLE_OK;
02411   }
02412   else
02413     return InitiateTransfer(conn);
02414 }
02415 
02416 /* for LIST and RETR responses */
02417 static CURLcode ftp_state_get_resp(struct connectdata *conn,
02418                                     int ftpcode,
02419                                     ftpstate instate)
02420 {
02421   CURLcode result = CURLE_OK;
02422   struct Curl_easy *data = conn->data;
02423   struct FTP *ftp = data->req.protop;
02424   char *buf = data->state.buffer;
02425 
02426   if((ftpcode == 150) || (ftpcode == 125)) {
02427 
02428     /*
02429       A;
02430       150 Opening BINARY mode data connection for /etc/passwd (2241
02431       bytes).  (ok, the file is being transferred)
02432 
02433       B:
02434       150 Opening ASCII mode data connection for /bin/ls
02435 
02436       C:
02437       150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
02438 
02439       D:
02440       150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
02441 
02442       E:
02443       125 Data connection already open; Transfer starting. */
02444 
02445     curl_off_t size=-1; /* default unknown size */
02446 
02447 
02448     /*
02449      * It appears that there are FTP-servers that return size 0 for files when
02450      * SIZE is used on the file while being in BINARY mode. To work around
02451      * that (stupid) behavior, we attempt to parse the RETR response even if
02452      * the SIZE returned size zero.
02453      *
02454      * Debugging help from Salvatore Sorrentino on February 26, 2003.
02455      */
02456 
02457     if((instate != FTP_LIST) &&
02458        !data->set.prefer_ascii &&
02459        (ftp->downloadsize < 1)) {
02460       /*
02461        * It seems directory listings either don't show the size or very
02462        * often uses size 0 anyway. ASCII transfers may very well turn out
02463        * that the transferred amount of data is not the same as this line
02464        * tells, why using this number in those cases only confuses us.
02465        *
02466        * Example D above makes this parsing a little tricky */
02467       char *bytes;
02468       bytes=strstr(buf, " bytes");
02469       if(bytes--) {
02470         long in=(long)(bytes-buf);
02471         /* this is a hint there is size information in there! ;-) */
02472         while(--in) {
02473           /* scan for the left parenthesis and break there */
02474           if('(' == *bytes)
02475             break;
02476           /* skip only digits */
02477           if(!ISDIGIT(*bytes)) {
02478             bytes=NULL;
02479             break;
02480           }
02481           /* one more estep backwards */
02482           bytes--;
02483         }
02484         /* if we have nothing but digits: */
02485         if(bytes++) {
02486           /* get the number! */
02487           size = curlx_strtoofft(bytes, NULL, 0);
02488         }
02489       }
02490     }
02491     else if(ftp->downloadsize > -1)
02492       size = ftp->downloadsize;
02493 
02494     if(size > data->req.maxdownload && data->req.maxdownload > 0)
02495       size = data->req.size = data->req.maxdownload;
02496     else if((instate != FTP_LIST) && (data->set.prefer_ascii))
02497       size = -1; /* kludge for servers that understate ASCII mode file size */
02498 
02499     infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
02500           data->req.maxdownload);
02501 
02502     if(instate != FTP_LIST)
02503       infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
02504             size);
02505 
02506     /* FTP download: */
02507     conn->proto.ftpc.state_saved = instate;
02508     conn->proto.ftpc.retr_size_saved = size;
02509 
02510     if(data->set.ftp_use_port) {
02511       bool connected;
02512 
02513       result = AllowServerConnect(conn, &connected);
02514       if(result)
02515         return result;
02516 
02517       if(!connected) {
02518         struct ftp_conn *ftpc = &conn->proto.ftpc;
02519         infof(data, "Data conn was not available immediately\n");
02520         state(conn, FTP_STOP);
02521         ftpc->wait_data_conn = TRUE;
02522       }
02523     }
02524     else
02525       return InitiateTransfer(conn);
02526   }
02527   else {
02528     if((instate == FTP_LIST) && (ftpcode == 450)) {
02529       /* simply no matching files in the dir listing */
02530       ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
02531       state(conn, FTP_STOP); /* this phase is over */
02532     }
02533     else {
02534       failf(data, "RETR response: %03d", ftpcode);
02535       return instate == FTP_RETR && ftpcode == 550?
02536         CURLE_REMOTE_FILE_NOT_FOUND:
02537         CURLE_FTP_COULDNT_RETR_FILE;
02538     }
02539   }
02540 
02541   return result;
02542 }
02543 
02544 /* after USER, PASS and ACCT */
02545 static CURLcode ftp_state_loggedin(struct connectdata *conn)
02546 {
02547   CURLcode result = CURLE_OK;
02548 
02549   if(conn->ssl[FIRSTSOCKET].use) {
02550     /* PBSZ = PROTECTION BUFFER SIZE.
02551 
02552     The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
02553 
02554     Specifically, the PROT command MUST be preceded by a PBSZ
02555     command and a PBSZ command MUST be preceded by a successful
02556     security data exchange (the TLS negotiation in this case)
02557 
02558     ... (and on page 8):
02559 
02560     Thus the PBSZ command must still be issued, but must have a
02561     parameter of '0' to indicate that no buffering is taking place
02562     and the data connection should not be encapsulated.
02563     */
02564     PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
02565     state(conn, FTP_PBSZ);
02566   }
02567   else {
02568     result = ftp_state_pwd(conn);
02569   }
02570   return result;
02571 }
02572 
02573 /* for USER and PASS responses */
02574 static CURLcode ftp_state_user_resp(struct connectdata *conn,
02575                                     int ftpcode,
02576                                     ftpstate instate)
02577 {
02578   CURLcode result = CURLE_OK;
02579   struct Curl_easy *data = conn->data;
02580   struct FTP *ftp = data->req.protop;
02581   struct ftp_conn *ftpc = &conn->proto.ftpc;
02582   (void)instate; /* no use for this yet */
02583 
02584   /* some need password anyway, and others just return 2xx ignored */
02585   if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
02586     /* 331 Password required for ...
02587        (the server requires to send the user's password too) */
02588     PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
02589     state(conn, FTP_PASS);
02590   }
02591   else if(ftpcode/100 == 2) {
02592     /* 230 User ... logged in.
02593        (the user logged in with or without password) */
02594     result = ftp_state_loggedin(conn);
02595   }
02596   else if(ftpcode == 332) {
02597     if(data->set.str[STRING_FTP_ACCOUNT]) {
02598       PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
02599       state(conn, FTP_ACCT);
02600     }
02601     else {
02602       failf(data, "ACCT requested but none available");
02603       result = CURLE_LOGIN_DENIED;
02604     }
02605   }
02606   else {
02607     /* All other response codes, like:
02608 
02609     530 User ... access denied
02610     (the server denies to log the specified user) */
02611 
02612     if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
02613         !conn->data->state.ftp_trying_alternative) {
02614       /* Ok, USER failed.  Let's try the supplied command. */
02615       PPSENDF(&conn->proto.ftpc.pp, "%s",
02616               conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
02617       conn->data->state.ftp_trying_alternative = TRUE;
02618       state(conn, FTP_USER);
02619       result = CURLE_OK;
02620     }
02621     else {
02622       failf(data, "Access denied: %03d", ftpcode);
02623       result = CURLE_LOGIN_DENIED;
02624     }
02625   }
02626   return result;
02627 }
02628 
02629 /* for ACCT response */
02630 static CURLcode ftp_state_acct_resp(struct connectdata *conn,
02631                                     int ftpcode)
02632 {
02633   CURLcode result = CURLE_OK;
02634   struct Curl_easy *data = conn->data;
02635   if(ftpcode != 230) {
02636     failf(data, "ACCT rejected by server: %03d", ftpcode);
02637     result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
02638   }
02639   else
02640     result = ftp_state_loggedin(conn);
02641 
02642   return result;
02643 }
02644 
02645 
02646 static CURLcode ftp_statemach_act(struct connectdata *conn)
02647 {
02648   CURLcode result;
02649   curl_socket_t sock = conn->sock[FIRSTSOCKET];
02650   struct Curl_easy *data=conn->data;
02651   int ftpcode;
02652   struct ftp_conn *ftpc = &conn->proto.ftpc;
02653   struct pingpong *pp = &ftpc->pp;
02654   static const char ftpauth[][4]  = { "SSL", "TLS" };
02655   size_t nread = 0;
02656 
02657   if(pp->sendleft)
02658     return Curl_pp_flushsend(pp);
02659 
02660   result = ftp_readresp(sock, pp, &ftpcode, &nread);
02661   if(result)
02662     return result;
02663 
02664   if(ftpcode) {
02665     /* we have now received a full FTP server response */
02666     switch(ftpc->state) {
02667     case FTP_WAIT220:
02668       if(ftpcode == 230)
02669         /* 230 User logged in - already! */
02670         return ftp_state_user_resp(conn, ftpcode, ftpc->state);
02671       else if(ftpcode != 220) {
02672         failf(data, "Got a %03d ftp-server response when 220 was expected",
02673               ftpcode);
02674         return CURLE_WEIRD_SERVER_REPLY;
02675       }
02676 
02677       /* We have received a 220 response fine, now we proceed. */
02678 #ifdef HAVE_GSSAPI
02679       if(data->set.krb) {
02680         /* If not anonymous login, try a secure login. Note that this
02681            procedure is still BLOCKING. */
02682 
02683         Curl_sec_request_prot(conn, "private");
02684         /* We set private first as default, in case the line below fails to
02685            set a valid level */
02686         Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
02687 
02688         if(Curl_sec_login(conn))
02689           infof(data, "Logging in with password in cleartext!\n");
02690         else
02691           infof(data, "Authentication successful\n");
02692       }
02693 #endif
02694 
02695       if(data->set.use_ssl &&
02696          (!conn->ssl[FIRSTSOCKET].use ||
02697           (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
02698            !conn->proxy_ssl[FIRSTSOCKET].use))) {
02699         /* We don't have a SSL/TLS connection yet, but FTPS is
02700            requested. Try a FTPS connection now */
02701 
02702         ftpc->count3=0;
02703         switch(data->set.ftpsslauth) {
02704         case CURLFTPAUTH_DEFAULT:
02705         case CURLFTPAUTH_SSL:
02706           ftpc->count2 = 1; /* add one to get next */
02707           ftpc->count1 = 0;
02708           break;
02709         case CURLFTPAUTH_TLS:
02710           ftpc->count2 = -1; /* subtract one to get next */
02711           ftpc->count1 = 1;
02712           break;
02713         default:
02714           failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
02715                 (int)data->set.ftpsslauth);
02716           return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
02717         }
02718         PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
02719         state(conn, FTP_AUTH);
02720       }
02721       else {
02722         result = ftp_state_user(conn);
02723         if(result)
02724           return result;
02725       }
02726 
02727       break;
02728 
02729     case FTP_AUTH:
02730       /* we have gotten the response to a previous AUTH command */
02731 
02732       /* RFC2228 (page 5) says:
02733        *
02734        * If the server is willing to accept the named security mechanism,
02735        * and does not require any security data, it must respond with
02736        * reply code 234/334.
02737        */
02738 
02739       if((ftpcode == 234) || (ftpcode == 334)) {
02740         /* Curl_ssl_connect is BLOCKING */
02741         result = Curl_ssl_connect(conn, FIRSTSOCKET);
02742         if(!result) {
02743           conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
02744           result = ftp_state_user(conn);
02745         }
02746       }
02747       else if(ftpc->count3 < 1) {
02748         ftpc->count3++;
02749         ftpc->count1 += ftpc->count2; /* get next attempt */
02750         result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
02751         /* remain in this same state */
02752       }
02753       else {
02754         if(data->set.use_ssl > CURLUSESSL_TRY)
02755           /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
02756           result = CURLE_USE_SSL_FAILED;
02757         else
02758           /* ignore the failure and continue */
02759           result = ftp_state_user(conn);
02760       }
02761 
02762       if(result)
02763         return result;
02764       break;
02765 
02766     case FTP_USER:
02767     case FTP_PASS:
02768       result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
02769       break;
02770 
02771     case FTP_ACCT:
02772       result = ftp_state_acct_resp(conn, ftpcode);
02773       break;
02774 
02775     case FTP_PBSZ:
02776       PPSENDF(&ftpc->pp, "PROT %c",
02777               data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
02778       state(conn, FTP_PROT);
02779 
02780       break;
02781 
02782     case FTP_PROT:
02783       if(ftpcode/100 == 2)
02784         /* We have enabled SSL for the data connection! */
02785         conn->bits.ftp_use_data_ssl =
02786           (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
02787       /* FTP servers typically responds with 500 if they decide to reject
02788          our 'P' request */
02789       else if(data->set.use_ssl > CURLUSESSL_CONTROL)
02790         /* we failed and bails out */
02791         return CURLE_USE_SSL_FAILED;
02792 
02793       if(data->set.ftp_ccc) {
02794         /* CCC - Clear Command Channel
02795          */
02796         PPSENDF(&ftpc->pp, "%s", "CCC");
02797         state(conn, FTP_CCC);
02798       }
02799       else {
02800         result = ftp_state_pwd(conn);
02801         if(result)
02802           return result;
02803       }
02804       break;
02805 
02806     case FTP_CCC:
02807       if(ftpcode < 500) {
02808         /* First shut down the SSL layer (note: this call will block) */
02809         result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
02810 
02811         if(result) {
02812           failf(conn->data, "Failed to clear the command channel (CCC)");
02813           return result;
02814         }
02815       }
02816 
02817       /* Then continue as normal */
02818       result = ftp_state_pwd(conn);
02819       if(result)
02820         return result;
02821       break;
02822 
02823     case FTP_PWD:
02824       if(ftpcode == 257) {
02825         char *ptr=&data->state.buffer[4];  /* start on the first letter */
02826         char *dir;
02827         char *store;
02828 
02829         dir = malloc(nread + 1);
02830         if(!dir)
02831           return CURLE_OUT_OF_MEMORY;
02832 
02833         /* Reply format is like
02834            257<space>[rubbish]"<directory-name>"<space><commentary> and the
02835            RFC959 says
02836 
02837            The directory name can contain any character; embedded
02838            double-quotes should be escaped by double-quotes (the
02839            "quote-doubling" convention).
02840         */
02841 
02842         /* scan for the first double-quote for non-standard responses */
02843         while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
02844               && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
02845           ptr++;
02846 
02847         if('\"' == *ptr) {
02848           /* it started good */
02849           ptr++;
02850           for(store = dir; *ptr;) {
02851             if('\"' == *ptr) {
02852               if('\"' == ptr[1]) {
02853                 /* "quote-doubling" */
02854                 *store = ptr[1];
02855                 ptr++;
02856               }
02857               else {
02858                 /* end of path */
02859                 *store = '\0'; /* zero terminate */
02860                 break; /* get out of this loop */
02861               }
02862             }
02863             else
02864               *store = *ptr;
02865             store++;
02866             ptr++;
02867           }
02868 
02869           /* If the path name does not look like an absolute path (i.e.: it
02870              does not start with a '/'), we probably need some server-dependent
02871              adjustments. For example, this is the case when connecting to
02872              an OS400 FTP server: this server supports two name syntaxes,
02873              the default one being incompatible with standard pathes. In
02874              addition, this server switches automatically to the regular path
02875              syntax when one is encountered in a command: this results in
02876              having an entrypath in the wrong syntax when later used in CWD.
02877                The method used here is to check the server OS: we do it only
02878              if the path name looks strange to minimize overhead on other
02879              systems. */
02880 
02881           if(!ftpc->server_os && dir[0] != '/') {
02882 
02883             result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
02884             if(result) {
02885               free(dir);
02886               return result;
02887             }
02888             Curl_safefree(ftpc->entrypath);
02889             ftpc->entrypath = dir; /* remember this */
02890             infof(data, "Entry path is '%s'\n", ftpc->entrypath);
02891             /* also save it where getinfo can access it: */
02892             data->state.most_recent_ftp_entrypath = ftpc->entrypath;
02893             state(conn, FTP_SYST);
02894             break;
02895           }
02896 
02897           Curl_safefree(ftpc->entrypath);
02898           ftpc->entrypath = dir; /* remember this */
02899           infof(data, "Entry path is '%s'\n", ftpc->entrypath);
02900           /* also save it where getinfo can access it: */
02901           data->state.most_recent_ftp_entrypath = ftpc->entrypath;
02902         }
02903         else {
02904           /* couldn't get the path */
02905           free(dir);
02906           infof(data, "Failed to figure out path\n");
02907         }
02908       }
02909       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
02910       DEBUGF(infof(data, "protocol connect phase DONE\n"));
02911       break;
02912 
02913     case FTP_SYST:
02914       if(ftpcode == 215) {
02915         char *ptr=&data->state.buffer[4];  /* start on the first letter */
02916         char *os;
02917         char *store;
02918 
02919         os = malloc(nread + 1);
02920         if(!os)
02921           return CURLE_OUT_OF_MEMORY;
02922 
02923         /* Reply format is like
02924            215<space><OS-name><space><commentary>
02925         */
02926         while(*ptr == ' ')
02927           ptr++;
02928         for(store = os; *ptr && *ptr != ' ';)
02929           *store++ = *ptr++;
02930         *store = '\0'; /* zero terminate */
02931 
02932         /* Check for special servers here. */
02933 
02934         if(strcasecompare(os, "OS/400")) {
02935           /* Force OS400 name format 1. */
02936           result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
02937           if(result) {
02938             free(os);
02939             return result;
02940           }
02941           /* remember target server OS */
02942           Curl_safefree(ftpc->server_os);
02943           ftpc->server_os = os;
02944           state(conn, FTP_NAMEFMT);
02945           break;
02946         }
02947         else {
02948           /* Nothing special for the target server. */
02949           /* remember target server OS */
02950           Curl_safefree(ftpc->server_os);
02951           ftpc->server_os = os;
02952         }
02953       }
02954       else {
02955         /* Cannot identify server OS. Continue anyway and cross fingers. */
02956       }
02957 
02958       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
02959       DEBUGF(infof(data, "protocol connect phase DONE\n"));
02960       break;
02961 
02962     case FTP_NAMEFMT:
02963       if(ftpcode == 250) {
02964         /* Name format change successful: reload initial path. */
02965         ftp_state_pwd(conn);
02966         break;
02967       }
02968 
02969       state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
02970       DEBUGF(infof(data, "protocol connect phase DONE\n"));
02971       break;
02972 
02973     case FTP_QUOTE:
02974     case FTP_POSTQUOTE:
02975     case FTP_RETR_PREQUOTE:
02976     case FTP_STOR_PREQUOTE:
02977       if((ftpcode >= 400) && !ftpc->count2) {
02978         /* failure response code, and not allowed to fail */
02979         failf(conn->data, "QUOT command failed with %03d", ftpcode);
02980         return CURLE_QUOTE_ERROR;
02981       }
02982       result = ftp_state_quote(conn, FALSE, ftpc->state);
02983       if(result)
02984         return result;
02985 
02986       break;
02987 
02988     case FTP_CWD:
02989       if(ftpcode/100 != 2) {
02990         /* failure to CWD there */
02991         if(conn->data->set.ftp_create_missing_dirs &&
02992            ftpc->count1 && !ftpc->count2) {
02993           /* try making it */
02994           ftpc->count2++; /* counter to prevent CWD-MKD loops */
02995           PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
02996           state(conn, FTP_MKD);
02997         }
02998         else {
02999           /* return failure */
03000           failf(data, "Server denied you to change to the given directory");
03001           ftpc->cwdfail = TRUE; /* don't remember this path as we failed
03002                                    to enter it */
03003           return CURLE_REMOTE_ACCESS_DENIED;
03004         }
03005       }
03006       else {
03007         /* success */
03008         ftpc->count2=0;
03009         if(++ftpc->count1 <= ftpc->dirdepth) {
03010           /* send next CWD */
03011           PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
03012         }
03013         else {
03014           result = ftp_state_mdtm(conn);
03015           if(result)
03016             return result;
03017         }
03018       }
03019       break;
03020 
03021     case FTP_MKD:
03022       if((ftpcode/100 != 2) && !ftpc->count3--) {
03023         /* failure to MKD the dir */
03024         failf(data, "Failed to MKD dir: %03d", ftpcode);
03025         return CURLE_REMOTE_ACCESS_DENIED;
03026       }
03027       state(conn, FTP_CWD);
03028       /* send CWD */
03029       PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
03030       break;
03031 
03032     case FTP_MDTM:
03033       result = ftp_state_mdtm_resp(conn, ftpcode);
03034       break;
03035 
03036     case FTP_TYPE:
03037     case FTP_LIST_TYPE:
03038     case FTP_RETR_TYPE:
03039     case FTP_STOR_TYPE:
03040       result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
03041       break;
03042 
03043     case FTP_SIZE:
03044     case FTP_RETR_SIZE:
03045     case FTP_STOR_SIZE:
03046       result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
03047       break;
03048 
03049     case FTP_REST:
03050     case FTP_RETR_REST:
03051       result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
03052       break;
03053 
03054     case FTP_PRET:
03055       if(ftpcode != 200) {
03056         /* there only is this one standard OK return code. */
03057         failf(data, "PRET command not accepted: %03d", ftpcode);
03058         return CURLE_FTP_PRET_FAILED;
03059       }
03060       result = ftp_state_use_pasv(conn);
03061       break;
03062 
03063     case FTP_PASV:
03064       result = ftp_state_pasv_resp(conn, ftpcode);
03065       break;
03066 
03067     case FTP_PORT:
03068       result = ftp_state_port_resp(conn, ftpcode);
03069       break;
03070 
03071     case FTP_LIST:
03072     case FTP_RETR:
03073       result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
03074       break;
03075 
03076     case FTP_STOR:
03077       result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
03078       break;
03079 
03080     case FTP_QUIT:
03081       /* fallthrough, just stop! */
03082     default:
03083       /* internal error */
03084       state(conn, FTP_STOP);
03085       break;
03086     }
03087   } /* if(ftpcode) */
03088 
03089   return result;
03090 }
03091 
03092 
03093 /* called repeatedly until done from multi.c */
03094 static CURLcode ftp_multi_statemach(struct connectdata *conn,
03095                                     bool *done)
03096 {
03097   struct ftp_conn *ftpc = &conn->proto.ftpc;
03098   CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
03099 
03100   /* Check for the state outside of the Curl_socket_check() return code checks
03101      since at times we are in fact already in this state when this function
03102      gets called. */
03103   *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
03104 
03105   return result;
03106 }
03107 
03108 static CURLcode ftp_block_statemach(struct connectdata *conn)
03109 {
03110   struct ftp_conn *ftpc = &conn->proto.ftpc;
03111   struct pingpong *pp = &ftpc->pp;
03112   CURLcode result = CURLE_OK;
03113 
03114   while(ftpc->state != FTP_STOP) {
03115     result = Curl_pp_statemach(pp, TRUE);
03116     if(result)
03117       break;
03118   }
03119 
03120   return result;
03121 }
03122 
03123 /*
03124  * ftp_connect() should do everything that is to be considered a part of
03125  * the connection phase.
03126  *
03127  * The variable 'done' points to will be TRUE if the protocol-layer connect
03128  * phase is done when this function returns, or FALSE if not.
03129  *
03130  */
03131 static CURLcode ftp_connect(struct connectdata *conn,
03132                                  bool *done) /* see description above */
03133 {
03134   CURLcode result;
03135   struct ftp_conn *ftpc = &conn->proto.ftpc;
03136   struct pingpong *pp = &ftpc->pp;
03137 
03138   *done = FALSE; /* default to not done yet */
03139 
03140   /* We always support persistent connections on ftp */
03141   connkeep(conn, "FTP default");
03142 
03143   pp->response_time = RESP_TIMEOUT; /* set default response time-out */
03144   pp->statemach_act = ftp_statemach_act;
03145   pp->endofresp = ftp_endofresp;
03146   pp->conn = conn;
03147 
03148   if(conn->handler->flags & PROTOPT_SSL) {
03149     /* BLOCKING */
03150     result = Curl_ssl_connect(conn, FIRSTSOCKET);
03151     if(result)
03152       return result;
03153   }
03154 
03155   Curl_pp_init(pp); /* init the generic pingpong data */
03156 
03157   /* When we connect, we start in the state where we await the 220
03158      response */
03159   state(conn, FTP_WAIT220);
03160 
03161   result = ftp_multi_statemach(conn, done);
03162 
03163   return result;
03164 }
03165 
03166 /***********************************************************************
03167  *
03168  * ftp_done()
03169  *
03170  * The DONE function. This does what needs to be done after a single DO has
03171  * performed.
03172  *
03173  * Input argument is already checked for validity.
03174  */
03175 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
03176                          bool premature)
03177 {
03178   struct Curl_easy *data = conn->data;
03179   struct FTP *ftp = data->req.protop;
03180   struct ftp_conn *ftpc = &conn->proto.ftpc;
03181   struct pingpong *pp = &ftpc->pp;
03182   ssize_t nread;
03183   int ftpcode;
03184   CURLcode result = CURLE_OK;
03185   char *path = NULL;
03186   const char *path_to_use = data->state.path;
03187 
03188   if(!ftp)
03189     return CURLE_OK;
03190 
03191   switch(status) {
03192   case CURLE_BAD_DOWNLOAD_RESUME:
03193   case CURLE_FTP_WEIRD_PASV_REPLY:
03194   case CURLE_FTP_PORT_FAILED:
03195   case CURLE_FTP_ACCEPT_FAILED:
03196   case CURLE_FTP_ACCEPT_TIMEOUT:
03197   case CURLE_FTP_COULDNT_SET_TYPE:
03198   case CURLE_FTP_COULDNT_RETR_FILE:
03199   case CURLE_PARTIAL_FILE:
03200   case CURLE_UPLOAD_FAILED:
03201   case CURLE_REMOTE_ACCESS_DENIED:
03202   case CURLE_FILESIZE_EXCEEDED:
03203   case CURLE_REMOTE_FILE_NOT_FOUND:
03204   case CURLE_WRITE_ERROR:
03205     /* the connection stays alive fine even though this happened */
03206     /* fall-through */
03207   case CURLE_OK: /* doesn't affect the control connection's status */
03208     if(!premature)
03209       break;
03210 
03211     /* until we cope better with prematurely ended requests, let them
03212      * fallback as if in complete failure */
03213   default:       /* by default, an error means the control connection is
03214                     wedged and should not be used anymore */
03215     ftpc->ctl_valid = FALSE;
03216     ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
03217                              current path, as this connection is going */
03218     connclose(conn, "FTP ended with bad error code");
03219     result = status;      /* use the already set error code */
03220     break;
03221   }
03222 
03223   /* now store a copy of the directory we are in */
03224   free(ftpc->prevpath);
03225 
03226   if(data->set.wildcardmatch) {
03227     if(data->set.chunk_end && ftpc->file) {
03228       data->set.chunk_end(data->wildcard.customptr);
03229     }
03230     ftpc->known_filesize = -1;
03231   }
03232 
03233   if(!result)
03234     /* get the "raw" path */
03235     result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE);
03236   if(result) {
03237     /* We can limp along anyway (and should try to since we may already be in
03238      * the error path) */
03239     ftpc->ctl_valid = FALSE; /* mark control connection as bad */
03240     connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
03241     ftpc->prevpath = NULL; /* no path remembering */
03242   }
03243   else {
03244     size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
03245     size_t dlen = strlen(path)-flen;
03246     if(!ftpc->cwdfail) {
03247       if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
03248         ftpc->prevpath = path;
03249         if(flen)
03250           /* if 'path' is not the whole string */
03251           ftpc->prevpath[dlen]=0; /* terminate */
03252       }
03253       else {
03254         /* we never changed dir */
03255         ftpc->prevpath=strdup("");
03256         free(path);
03257       }
03258       if(ftpc->prevpath)
03259         infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
03260     }
03261     else {
03262       ftpc->prevpath = NULL; /* no path */
03263       free(path);
03264     }
03265   }
03266   /* free the dir tree and file parts */
03267   freedirs(ftpc);
03268 
03269   /* shut down the socket to inform the server we're done */
03270 
03271 #ifdef _WIN32_WCE
03272   shutdown(conn->sock[SECONDARYSOCKET], 2);  /* SD_BOTH */
03273 #endif
03274 
03275   if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
03276     if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
03277       /* partial download completed */
03278       result = Curl_pp_sendf(pp, "%s", "ABOR");
03279       if(result) {
03280         failf(data, "Failure sending ABOR command: %s",
03281               curl_easy_strerror(result));
03282         ftpc->ctl_valid = FALSE; /* mark control connection as bad */
03283         connclose(conn, "ABOR command failed"); /* connection closure */
03284       }
03285     }
03286 
03287     if(conn->ssl[SECONDARYSOCKET].use) {
03288       /* The secondary socket is using SSL so we must close down that part
03289          first before we close the socket for real */
03290       Curl_ssl_close(conn, SECONDARYSOCKET);
03291 
03292       /* Note that we keep "use" set to TRUE since that (next) connection is
03293          still requested to use SSL */
03294     }
03295     close_secondarysocket(conn);
03296   }
03297 
03298   if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
03299      pp->pending_resp && !premature) {
03300     /*
03301      * Let's see what the server says about the transfer we just performed,
03302      * but lower the timeout as sometimes this connection has died while the
03303      * data has been transferred. This happens when doing through NATs etc that
03304      * abandon old silent connections.
03305      */
03306     long old_time = pp->response_time;
03307 
03308     pp->response_time = 60*1000; /* give it only a minute for now */
03309     pp->response = Curl_tvnow(); /* timeout relative now */
03310 
03311     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
03312 
03313     pp->response_time = old_time; /* set this back to previous value */
03314 
03315     if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
03316       failf(data, "control connection looks dead");
03317       ftpc->ctl_valid = FALSE; /* mark control connection as bad */
03318       connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
03319     }
03320 
03321     if(result)
03322       return result;
03323 
03324     if(ftpc->dont_check && data->req.maxdownload > 0) {
03325       /* we have just sent ABOR and there is no reliable way to check if it was
03326        * successful or not; we have to close the connection now */
03327       infof(data, "partial download completed, closing connection\n");
03328       connclose(conn, "Partial download with no ability to check");
03329       return result;
03330     }
03331 
03332     if(!ftpc->dont_check) {
03333       /* 226 Transfer complete, 250 Requested file action okay, completed. */
03334       if((ftpcode != 226) && (ftpcode != 250)) {
03335         failf(data, "server did not report OK, got %d", ftpcode);
03336         result = CURLE_PARTIAL_FILE;
03337       }
03338     }
03339   }
03340 
03341   if(result || premature)
03342     /* the response code from the transfer showed an error already so no
03343        use checking further */
03344     ;
03345   else if(data->set.upload) {
03346     if((-1 != data->state.infilesize) &&
03347        (data->state.infilesize != *ftp->bytecountp) &&
03348        !data->set.crlf &&
03349        (ftp->transfer == FTPTRANSFER_BODY)) {
03350       failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
03351             " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
03352             *ftp->bytecountp, data->state.infilesize);
03353       result = CURLE_PARTIAL_FILE;
03354     }
03355   }
03356   else {
03357     if((-1 != data->req.size) &&
03358        (data->req.size != *ftp->bytecountp) &&
03359 #ifdef CURL_DO_LINEEND_CONV
03360        /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
03361         * we'll check to see if the discrepancy can be explained by the number
03362         * of CRLFs we've changed to LFs.
03363         */
03364        ((data->req.size + data->state.crlf_conversions) !=
03365         *ftp->bytecountp) &&
03366 #endif /* CURL_DO_LINEEND_CONV */
03367        (data->req.maxdownload != *ftp->bytecountp)) {
03368       failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
03369             " bytes", *ftp->bytecountp);
03370       result = CURLE_PARTIAL_FILE;
03371     }
03372     else if(!ftpc->dont_check &&
03373             !*ftp->bytecountp &&
03374             (data->req.size>0)) {
03375       failf(data, "No data was received!");
03376       result = CURLE_FTP_COULDNT_RETR_FILE;
03377     }
03378   }
03379 
03380   /* clear these for next connection */
03381   ftp->transfer = FTPTRANSFER_BODY;
03382   ftpc->dont_check = FALSE;
03383 
03384   /* Send any post-transfer QUOTE strings? */
03385   if(!status && !result && !premature && data->set.postquote)
03386     result = ftp_sendquote(conn, data->set.postquote);
03387 
03388   return result;
03389 }
03390 
03391 /***********************************************************************
03392  *
03393  * ftp_sendquote()
03394  *
03395  * Where a 'quote' means a list of custom commands to send to the server.
03396  * The quote list is passed as an argument.
03397  *
03398  * BLOCKING
03399  */
03400 
03401 static
03402 CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
03403 {
03404   struct curl_slist *item;
03405   ssize_t nread;
03406   int ftpcode;
03407   CURLcode result;
03408   struct ftp_conn *ftpc = &conn->proto.ftpc;
03409   struct pingpong *pp = &ftpc->pp;
03410 
03411   item = quote;
03412   while(item) {
03413     if(item->data) {
03414       char *cmd = item->data;
03415       bool acceptfail = FALSE;
03416 
03417       /* if a command starts with an asterisk, which a legal FTP command never
03418          can, the command will be allowed to fail without it causing any
03419          aborts or cancels etc. It will cause libcurl to act as if the command
03420          is successful, whatever the server reponds. */
03421 
03422       if(cmd[0] == '*') {
03423         cmd++;
03424         acceptfail = TRUE;
03425       }
03426 
03427       PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
03428 
03429       pp->response = Curl_tvnow(); /* timeout relative now */
03430 
03431       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
03432       if(result)
03433         return result;
03434 
03435       if(!acceptfail && (ftpcode >= 400)) {
03436         failf(conn->data, "QUOT string not accepted: %s", cmd);
03437         return CURLE_QUOTE_ERROR;
03438       }
03439     }
03440 
03441     item = item->next;
03442   }
03443 
03444   return CURLE_OK;
03445 }
03446 
03447 /***********************************************************************
03448  *
03449  * ftp_need_type()
03450  *
03451  * Returns TRUE if we in the current situation should send TYPE
03452  */
03453 static int ftp_need_type(struct connectdata *conn,
03454                          bool ascii_wanted)
03455 {
03456   return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
03457 }
03458 
03459 /***********************************************************************
03460  *
03461  * ftp_nb_type()
03462  *
03463  * Set TYPE. We only deal with ASCII or BINARY so this function
03464  * sets one of them.
03465  * If the transfer type is not sent, simulate on OK response in newstate
03466  */
03467 static CURLcode ftp_nb_type(struct connectdata *conn,
03468                             bool ascii, ftpstate newstate)
03469 {
03470   struct ftp_conn *ftpc = &conn->proto.ftpc;
03471   CURLcode result;
03472   char want = (char)(ascii?'A':'I');
03473 
03474   if(ftpc->transfertype == want) {
03475     state(conn, newstate);
03476     return ftp_state_type_resp(conn, 200, newstate);
03477   }
03478 
03479   PPSENDF(&ftpc->pp, "TYPE %c", want);
03480   state(conn, newstate);
03481 
03482   /* keep track of our current transfer type */
03483   ftpc->transfertype = want;
03484   return CURLE_OK;
03485 }
03486 
03487 /***************************************************************************
03488  *
03489  * ftp_pasv_verbose()
03490  *
03491  * This function only outputs some informationals about this second connection
03492  * when we've issued a PASV command before and thus we have connected to a
03493  * possibly new IP address.
03494  *
03495  */
03496 #ifndef CURL_DISABLE_VERBOSE_STRINGS
03497 static void
03498 ftp_pasv_verbose(struct connectdata *conn,
03499                  Curl_addrinfo *ai,
03500                  char *newhost, /* ascii version */
03501                  int port)
03502 {
03503   char buf[256];
03504   Curl_printable_address(ai, buf, sizeof(buf));
03505   infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
03506 }
03507 #endif
03508 
03509 /*
03510   Check if this is a range download, and if so, set the internal variables
03511   properly.
03512  */
03513 
03514 static CURLcode ftp_range(struct connectdata *conn)
03515 {
03516   curl_off_t from, to;
03517   char *ptr;
03518   char *ptr2;
03519   struct Curl_easy *data = conn->data;
03520   struct ftp_conn *ftpc = &conn->proto.ftpc;
03521 
03522   if(data->state.use_range && data->state.range) {
03523     from=curlx_strtoofft(data->state.range, &ptr, 0);
03524     while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
03525       ptr++;
03526     to=curlx_strtoofft(ptr, &ptr2, 0);
03527     if(ptr == ptr2) {
03528       /* we didn't get any digit */
03529       to=-1;
03530     }
03531     if((-1 == to) && (from>=0)) {
03532       /* X - */
03533       data->state.resume_from = from;
03534       DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
03535                    " to end of file\n", from));
03536     }
03537     else if(from < 0) {
03538       /* -Y */
03539       data->req.maxdownload = -from;
03540       data->state.resume_from = from;
03541       DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
03542                    " bytes\n", -from));
03543     }
03544     else {
03545       /* X-Y */
03546       data->req.maxdownload = (to-from)+1; /* include last byte */
03547       data->state.resume_from = from;
03548       DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
03549                    " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
03550                    from, data->req.maxdownload));
03551     }
03552     DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
03553                  " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
03554                  CURL_FORMAT_CURL_OFF_T " bytes\n",
03555                  from, to, data->req.maxdownload));
03556     ftpc->dont_check = TRUE; /* dont check for successful transfer */
03557   }
03558   else
03559     data->req.maxdownload = -1;
03560   return CURLE_OK;
03561 }
03562 
03563 
03564 /*
03565  * ftp_do_more()
03566  *
03567  * This function shall be called when the second FTP (data) connection is
03568  * connected.
03569  *
03570  * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
03571  * (which basically is only for when PASV is being sent to retry a failed
03572  * EPSV).
03573  */
03574 
03575 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
03576 {
03577   struct Curl_easy *data=conn->data;
03578   struct ftp_conn *ftpc = &conn->proto.ftpc;
03579   CURLcode result = CURLE_OK;
03580   bool connected = FALSE;
03581   bool complete = FALSE;
03582 
03583   /* the ftp struct is inited in ftp_connect() */
03584   struct FTP *ftp = data->req.protop;
03585 
03586   /* if the second connection isn't done yet, wait for it */
03587   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
03588     if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
03589       /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
03590          aren't used so we blank their arguments. TODO: make this nicer */
03591       result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE);
03592 
03593       return result;
03594     }
03595 
03596     result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
03597 
03598     /* Ready to do more? */
03599     if(connected) {
03600       DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
03601     }
03602     else {
03603       if(result && (ftpc->count1 == 0)) {
03604         *completep = -1; /* go back to DOING please */
03605         /* this is a EPSV connect failing, try PASV instead */
03606         return ftp_epsv_disable(conn);
03607       }
03608       return result;
03609     }
03610   }
03611 
03612   result = Curl_proxy_connect(conn, SECONDARYSOCKET);
03613   if(result)
03614     return result;
03615 
03616   if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
03617     return result;
03618 
03619   if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
03620      conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE)
03621     return result;
03622 
03623 
03624   if(ftpc->state) {
03625     /* already in a state so skip the intial commands.
03626        They are only done to kickstart the do_more state */
03627     result = ftp_multi_statemach(conn, &complete);
03628 
03629     *completep = (int)complete;
03630 
03631     /* if we got an error or if we don't wait for a data connection return
03632        immediately */
03633     if(result || (ftpc->wait_data_conn != TRUE))
03634       return result;
03635 
03636     if(ftpc->wait_data_conn)
03637       /* if we reach the end of the FTP state machine here, *complete will be
03638          TRUE but so is ftpc->wait_data_conn, which says we need to wait for
03639          the data connection and therefore we're not actually complete */
03640       *completep = 0;
03641   }
03642 
03643   if(ftp->transfer <= FTPTRANSFER_INFO) {
03644     /* a transfer is about to take place, or if not a file name was given
03645        so we'll do a SIZE on it later and then we need the right TYPE first */
03646 
03647     if(ftpc->wait_data_conn == TRUE) {
03648       bool serv_conned;
03649 
03650       result = ReceivedServerConnect(conn, &serv_conned);
03651       if(result)
03652         return result; /* Failed to accept data connection */
03653 
03654       if(serv_conned) {
03655         /* It looks data connection is established */
03656         result = AcceptServerConnect(conn);
03657         ftpc->wait_data_conn = FALSE;
03658         if(!result)
03659           result = InitiateTransfer(conn);
03660 
03661         if(result)
03662           return result;
03663 
03664         *completep = 1; /* this state is now complete when the server has
03665                            connected back to us */
03666       }
03667     }
03668     else if(data->set.upload) {
03669       result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
03670       if(result)
03671         return result;
03672 
03673       result = ftp_multi_statemach(conn, &complete);
03674       if(ftpc->wait_data_conn)
03675         /* if we reach the end of the FTP state machine here, *complete will be
03676            TRUE but so is ftpc->wait_data_conn, which says we need to wait for
03677            the data connection and therefore we're not actually complete */
03678         *completep = 0;
03679       else
03680         *completep = (int)complete;
03681     }
03682     else {
03683       /* download */
03684       ftp->downloadsize = -1; /* unknown as of yet */
03685 
03686       result = ftp_range(conn);
03687       if(result)
03688         ;
03689       else if(data->set.ftp_list_only || !ftpc->file) {
03690         /* The specified path ends with a slash, and therefore we think this
03691            is a directory that is requested, use LIST. But before that we
03692            need to set ASCII transfer mode. */
03693 
03694         /* But only if a body transfer was requested. */
03695         if(ftp->transfer == FTPTRANSFER_BODY) {
03696           result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
03697           if(result)
03698             return result;
03699         }
03700         /* otherwise just fall through */
03701       }
03702       else {
03703         result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
03704         if(result)
03705           return result;
03706       }
03707 
03708       result = ftp_multi_statemach(conn, &complete);
03709       *completep = (int)complete;
03710     }
03711     return result;
03712   }
03713 
03714   if(!result && (ftp->transfer != FTPTRANSFER_BODY))
03715     /* no data to transfer. FIX: it feels like a kludge to have this here
03716        too! */
03717     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
03718 
03719   if(!ftpc->wait_data_conn) {
03720     /* no waiting for the data connection so this is now complete */
03721     *completep = 1;
03722     DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
03723   }
03724 
03725   return result;
03726 }
03727 
03728 
03729 
03730 /***********************************************************************
03731  *
03732  * ftp_perform()
03733  *
03734  * This is the actual DO function for FTP. Get a file/directory according to
03735  * the options previously setup.
03736  */
03737 
03738 static
03739 CURLcode ftp_perform(struct connectdata *conn,
03740                      bool *connected,  /* connect status after PASV / PORT */
03741                      bool *dophase_done)
03742 {
03743   /* this is FTP and no proxy */
03744   CURLcode result=CURLE_OK;
03745 
03746   DEBUGF(infof(conn->data, "DO phase starts\n"));
03747 
03748   if(conn->data->set.opt_no_body) {
03749     /* requested no body means no transfer... */
03750     struct FTP *ftp = conn->data->req.protop;
03751     ftp->transfer = FTPTRANSFER_INFO;
03752   }
03753 
03754   *dophase_done = FALSE; /* not done yet */
03755 
03756   /* start the first command in the DO phase */
03757   result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
03758   if(result)
03759     return result;
03760 
03761   /* run the state-machine */
03762   result = ftp_multi_statemach(conn, dophase_done);
03763 
03764   *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
03765 
03766   infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
03767 
03768   if(*dophase_done)
03769     DEBUGF(infof(conn->data, "DO phase is complete1\n"));
03770 
03771   return result;
03772 }
03773 
03774 static void wc_data_dtor(void *ptr)
03775 {
03776   struct ftp_wc_tmpdata *tmp = ptr;
03777   if(tmp)
03778     Curl_ftp_parselist_data_free(&tmp->parser);
03779   free(tmp);
03780 }
03781 
03782 static CURLcode init_wc_data(struct connectdata *conn)
03783 {
03784   char *last_slash;
03785   char *path = conn->data->state.path;
03786   struct WildcardData *wildcard = &(conn->data->wildcard);
03787   CURLcode result = CURLE_OK;
03788   struct ftp_wc_tmpdata *ftp_tmp;
03789 
03790   last_slash = strrchr(conn->data->state.path, '/');
03791   if(last_slash) {
03792     last_slash++;
03793     if(last_slash[0] == '\0') {
03794       wildcard->state = CURLWC_CLEAN;
03795       result = ftp_parse_url_path(conn);
03796       return result;
03797     }
03798     else {
03799       wildcard->pattern = strdup(last_slash);
03800       if(!wildcard->pattern)
03801         return CURLE_OUT_OF_MEMORY;
03802       last_slash[0] = '\0'; /* cut file from path */
03803     }
03804   }
03805   else { /* there is only 'wildcard pattern' or nothing */
03806     if(path[0]) {
03807       wildcard->pattern = strdup(path);
03808       if(!wildcard->pattern)
03809         return CURLE_OUT_OF_MEMORY;
03810       path[0] = '\0';
03811     }
03812     else { /* only list */
03813       wildcard->state = CURLWC_CLEAN;
03814       result = ftp_parse_url_path(conn);
03815       return result;
03816     }
03817   }
03818 
03819   /* program continues only if URL is not ending with slash, allocate needed
03820      resources for wildcard transfer */
03821 
03822   /* allocate ftp protocol specific temporary wildcard data */
03823   ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
03824   if(!ftp_tmp) {
03825     Curl_safefree(wildcard->pattern);
03826     return CURLE_OUT_OF_MEMORY;
03827   }
03828 
03829   /* INITIALIZE parselist structure */
03830   ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
03831   if(!ftp_tmp->parser) {
03832     Curl_safefree(wildcard->pattern);
03833     free(ftp_tmp);
03834     return CURLE_OUT_OF_MEMORY;
03835   }
03836 
03837   wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
03838   wildcard->tmp_dtor = wc_data_dtor;
03839 
03840   /* wildcard does not support NOCWD option (assert it?) */
03841   if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
03842     conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
03843 
03844   /* try to parse ftp url */
03845   result = ftp_parse_url_path(conn);
03846   if(result) {
03847     Curl_safefree(wildcard->pattern);
03848     wildcard->tmp_dtor(wildcard->tmp);
03849     wildcard->tmp_dtor = ZERO_NULL;
03850     wildcard->tmp = NULL;
03851     return result;
03852   }
03853 
03854   wildcard->path = strdup(conn->data->state.path);
03855   if(!wildcard->path) {
03856     Curl_safefree(wildcard->pattern);
03857     wildcard->tmp_dtor(wildcard->tmp);
03858     wildcard->tmp_dtor = ZERO_NULL;
03859     wildcard->tmp = NULL;
03860     return CURLE_OUT_OF_MEMORY;
03861   }
03862 
03863   /* backup old write_function */
03864   ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
03865   /* parsing write function */
03866   conn->data->set.fwrite_func = Curl_ftp_parselist;
03867   /* backup old file descriptor */
03868   ftp_tmp->backup.file_descriptor = conn->data->set.out;
03869   /* let the writefunc callback know what curl pointer is working with */
03870   conn->data->set.out = conn;
03871 
03872   infof(conn->data, "Wildcard - Parsing started\n");
03873   return CURLE_OK;
03874 }
03875 
03876 /* This is called recursively */
03877 static CURLcode wc_statemach(struct connectdata *conn)
03878 {
03879   struct WildcardData * const wildcard = &(conn->data->wildcard);
03880   CURLcode result = CURLE_OK;
03881 
03882   switch(wildcard->state) {
03883   case CURLWC_INIT:
03884     result = init_wc_data(conn);
03885     if(wildcard->state == CURLWC_CLEAN)
03886       /* only listing! */
03887       break;
03888     else
03889       wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
03890     break;
03891 
03892   case CURLWC_MATCHING: {
03893     /* In this state is LIST response successfully parsed, so lets restore
03894        previous WRITEFUNCTION callback and WRITEDATA pointer */
03895     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
03896     conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
03897     conn->data->set.out = ftp_tmp->backup.file_descriptor;
03898     ftp_tmp->backup.write_function = ZERO_NULL;
03899     ftp_tmp->backup.file_descriptor = NULL;
03900     wildcard->state = CURLWC_DOWNLOADING;
03901 
03902     if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
03903       /* error found in LIST parsing */
03904       wildcard->state = CURLWC_CLEAN;
03905       return wc_statemach(conn);
03906     }
03907     else if(wildcard->filelist->size == 0) {
03908       /* no corresponding file */
03909       wildcard->state = CURLWC_CLEAN;
03910       return CURLE_REMOTE_FILE_NOT_FOUND;
03911     }
03912     return wc_statemach(conn);
03913   }
03914 
03915   case CURLWC_DOWNLOADING: {
03916     /* filelist has at least one file, lets get first one */
03917     struct ftp_conn *ftpc = &conn->proto.ftpc;
03918     struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
03919 
03920     char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
03921     if(!tmp_path)
03922       return CURLE_OUT_OF_MEMORY;
03923 
03924     /* switch default "state.pathbuffer" and tmp_path, good to see
03925        ftp_parse_url_path function to understand this trick */
03926     Curl_safefree(conn->data->state.pathbuffer);
03927     conn->data->state.pathbuffer = tmp_path;
03928     conn->data->state.path = tmp_path;
03929 
03930     infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
03931     if(conn->data->set.chunk_bgn) {
03932       long userresponse = conn->data->set.chunk_bgn(
03933           finfo, wildcard->customptr, (int)wildcard->filelist->size);
03934       switch(userresponse) {
03935       case CURL_CHUNK_BGN_FUNC_SKIP:
03936         infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
03937               finfo->filename);
03938         wildcard->state = CURLWC_SKIP;
03939         return wc_statemach(conn);
03940       case CURL_CHUNK_BGN_FUNC_FAIL:
03941         return CURLE_CHUNK_FAILED;
03942       }
03943     }
03944 
03945     if(finfo->filetype != CURLFILETYPE_FILE) {
03946       wildcard->state = CURLWC_SKIP;
03947       return wc_statemach(conn);
03948     }
03949 
03950     if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
03951       ftpc->known_filesize = finfo->size;
03952 
03953     result = ftp_parse_url_path(conn);
03954     if(result)
03955       return result;
03956 
03957     /* we don't need the Curl_fileinfo of first file anymore */
03958     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
03959 
03960     if(wildcard->filelist->size == 0) { /* remains only one file to down. */
03961       wildcard->state = CURLWC_CLEAN;
03962       /* after that will be ftp_do called once again and no transfer
03963          will be done because of CURLWC_CLEAN state */
03964       return CURLE_OK;
03965     }
03966   } break;
03967 
03968   case CURLWC_SKIP: {
03969     if(conn->data->set.chunk_end)
03970       conn->data->set.chunk_end(conn->data->wildcard.customptr);
03971     Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
03972     wildcard->state = (wildcard->filelist->size == 0) ?
03973                       CURLWC_CLEAN : CURLWC_DOWNLOADING;
03974     return wc_statemach(conn);
03975   }
03976 
03977   case CURLWC_CLEAN: {
03978     struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
03979     result = CURLE_OK;
03980     if(ftp_tmp)
03981       result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
03982 
03983     wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
03984   } break;
03985 
03986   case CURLWC_DONE:
03987   case CURLWC_ERROR:
03988     break;
03989   }
03990 
03991   return result;
03992 }
03993 
03994 /***********************************************************************
03995  *
03996  * ftp_do()
03997  *
03998  * This function is registered as 'curl_do' function. It decodes the path
03999  * parts etc as a wrapper to the actual DO function (ftp_perform).
04000  *
04001  * The input argument is already checked for validity.
04002  */
04003 static CURLcode ftp_do(struct connectdata *conn, bool *done)
04004 {
04005   CURLcode result = CURLE_OK;
04006   struct ftp_conn *ftpc = &conn->proto.ftpc;
04007 
04008   *done = FALSE; /* default to false */
04009   ftpc->wait_data_conn = FALSE; /* default to no such wait */
04010 
04011   if(conn->data->set.wildcardmatch) {
04012     result = wc_statemach(conn);
04013     if(conn->data->wildcard.state == CURLWC_SKIP ||
04014       conn->data->wildcard.state == CURLWC_DONE) {
04015       /* do not call ftp_regular_transfer */
04016       return CURLE_OK;
04017     }
04018     if(result) /* error, loop or skipping the file */
04019       return result;
04020   }
04021   else { /* no wildcard FSM needed */
04022     result = ftp_parse_url_path(conn);
04023     if(result)
04024       return result;
04025   }
04026 
04027   result = ftp_regular_transfer(conn, done);
04028 
04029   return result;
04030 }
04031 
04032 
04033 CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
04034 {
04035   ssize_t bytes_written;
04036 #define SBUF_SIZE 1024
04037   char s[SBUF_SIZE];
04038   size_t write_len;
04039   char *sptr=s;
04040   CURLcode result = CURLE_OK;
04041 #ifdef HAVE_GSSAPI
04042   enum protection_level data_sec = conn->data_prot;
04043 #endif
04044 
04045   write_len = strlen(cmd);
04046   if(write_len > (sizeof(s) -3))
04047     return CURLE_BAD_FUNCTION_ARGUMENT;
04048 
04049   strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
04050   write_len +=2;
04051 
04052   bytes_written=0;
04053 
04054   result = Curl_convert_to_network(conn->data, s, write_len);
04055   /* Curl_convert_to_network calls failf if unsuccessful */
04056   if(result)
04057     return result;
04058 
04059   for(;;) {
04060 #ifdef HAVE_GSSAPI
04061     conn->data_prot = PROT_CMD;
04062 #endif
04063     result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
04064                         &bytes_written);
04065 #ifdef HAVE_GSSAPI
04066     DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
04067     conn->data_prot = data_sec;
04068 #endif
04069 
04070     if(result)
04071       break;
04072 
04073     if(conn->data->set.verbose)
04074       Curl_debug(conn->data, CURLINFO_HEADER_OUT,
04075                  sptr, (size_t)bytes_written, conn);
04076 
04077     if(bytes_written != (ssize_t)write_len) {
04078       write_len -= bytes_written;
04079       sptr += bytes_written;
04080     }
04081     else
04082       break;
04083   }
04084 
04085   return result;
04086 }
04087 
04088 /***********************************************************************
04089  *
04090  * ftp_quit()
04091  *
04092  * This should be called before calling sclose() on an ftp control connection
04093  * (not data connections). We should then wait for the response from the
04094  * server before returning. The calling code should then try to close the
04095  * connection.
04096  *
04097  */
04098 static CURLcode ftp_quit(struct connectdata *conn)
04099 {
04100   CURLcode result = CURLE_OK;
04101 
04102   if(conn->proto.ftpc.ctl_valid) {
04103     result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
04104     if(result) {
04105       failf(conn->data, "Failure sending QUIT command: %s",
04106             curl_easy_strerror(result));
04107       conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
04108       connclose(conn, "QUIT command failed"); /* mark for connection closure */
04109       state(conn, FTP_STOP);
04110       return result;
04111     }
04112 
04113     state(conn, FTP_QUIT);
04114 
04115     result = ftp_block_statemach(conn);
04116   }
04117 
04118   return result;
04119 }
04120 
04121 /***********************************************************************
04122  *
04123  * ftp_disconnect()
04124  *
04125  * Disconnect from an FTP server. Cleanup protocol-specific per-connection
04126  * resources. BLOCKING.
04127  */
04128 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
04129 {
04130   struct ftp_conn *ftpc= &conn->proto.ftpc;
04131   struct pingpong *pp = &ftpc->pp;
04132 
04133   /* We cannot send quit unconditionally. If this connection is stale or
04134      bad in any way, sending quit and waiting around here will make the
04135      disconnect wait in vain and cause more problems than we need to.
04136 
04137      ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
04138      will try to send the QUIT command, otherwise it will just return.
04139   */
04140   if(dead_connection)
04141     ftpc->ctl_valid = FALSE;
04142 
04143   /* The FTP session may or may not have been allocated/setup at this point! */
04144   (void)ftp_quit(conn); /* ignore errors on the QUIT */
04145 
04146   if(ftpc->entrypath) {
04147     struct Curl_easy *data = conn->data;
04148     if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
04149       data->state.most_recent_ftp_entrypath = NULL;
04150     }
04151     free(ftpc->entrypath);
04152     ftpc->entrypath = NULL;
04153   }
04154 
04155   freedirs(ftpc);
04156   free(ftpc->prevpath);
04157   ftpc->prevpath = NULL;
04158   free(ftpc->server_os);
04159   ftpc->server_os = NULL;
04160 
04161   Curl_pp_disconnect(pp);
04162 
04163 #ifdef HAVE_GSSAPI
04164   Curl_sec_end(conn);
04165 #endif
04166 
04167   return CURLE_OK;
04168 }
04169 
04170 /***********************************************************************
04171  *
04172  * ftp_parse_url_path()
04173  *
04174  * Parse the URL path into separate path components.
04175  *
04176  */
04177 static
04178 CURLcode ftp_parse_url_path(struct connectdata *conn)
04179 {
04180   struct Curl_easy *data = conn->data;
04181   /* the ftp struct is already inited in ftp_connect() */
04182   struct FTP *ftp = data->req.protop;
04183   struct ftp_conn *ftpc = &conn->proto.ftpc;
04184   const char *slash_pos;  /* position of the first '/' char in curpos */
04185   const char *path_to_use = data->state.path;
04186   const char *cur_pos;
04187   const char *filename = NULL;
04188 
04189   cur_pos = path_to_use; /* current position in path. point at the begin of
04190                             next path component */
04191 
04192   ftpc->ctl_valid = FALSE;
04193   ftpc->cwdfail = FALSE;
04194 
04195   switch(data->set.ftp_filemethod) {
04196   case FTPFILE_NOCWD:
04197     /* fastest, but less standard-compliant */
04198 
04199     /*
04200       The best time to check whether the path is a file or directory is right
04201       here. so:
04202 
04203       the first condition in the if() right here, is there just in case
04204       someone decides to set path to NULL one day
04205    */
04206     if(path_to_use[0] &&
04207        (path_to_use[strlen(path_to_use) - 1] != '/') )
04208       filename = path_to_use;  /* this is a full file path */
04209     /*
04210       else {
04211         ftpc->file is not used anywhere other than for operations on a file.
04212         In other words, never for directory operations.
04213         So we can safely leave filename as NULL here and use it as a
04214         argument in dir/file decisions.
04215       }
04216     */
04217     break;
04218 
04219   case FTPFILE_SINGLECWD:
04220     /* get the last slash */
04221     if(!path_to_use[0]) {
04222       /* no dir, no file */
04223       ftpc->dirdepth = 0;
04224       break;
04225     }
04226     slash_pos=strrchr(cur_pos, '/');
04227     if(slash_pos || !*cur_pos) {
04228       size_t dirlen = slash_pos-cur_pos;
04229       CURLcode result;
04230 
04231       ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
04232       if(!ftpc->dirs)
04233         return CURLE_OUT_OF_MEMORY;
04234 
04235       if(!dirlen)
04236         dirlen++;
04237 
04238       result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
04239                               slash_pos ? dirlen : 1,
04240                               &ftpc->dirs[0], NULL,
04241                               FALSE);
04242       if(result) {
04243         freedirs(ftpc);
04244         return result;
04245       }
04246       ftpc->dirdepth = 1; /* we consider it to be a single dir */
04247       filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
04248     }
04249     else
04250       filename = cur_pos;  /* this is a file name only */
04251     break;
04252 
04253   default: /* allow pretty much anything */
04254   case FTPFILE_MULTICWD:
04255     ftpc->dirdepth = 0;
04256     ftpc->diralloc = 5; /* default dir depth to allocate */
04257     ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
04258     if(!ftpc->dirs)
04259       return CURLE_OUT_OF_MEMORY;
04260 
04261     /* we have a special case for listing the root dir only */
04262     if(!strcmp(path_to_use, "/")) {
04263       cur_pos++; /* make it point to the zero byte */
04264       ftpc->dirs[0] = strdup("/");
04265       ftpc->dirdepth++;
04266     }
04267     else {
04268       /* parse the URL path into separate path components */
04269       while((slash_pos = strchr(cur_pos, '/')) != NULL) {
04270         /* 1 or 0 pointer offset to indicate absolute directory */
04271         ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
04272                                 (ftpc->dirdepth == 0))?1:0;
04273 
04274         /* seek out the next path component */
04275         if(slash_pos-cur_pos) {
04276           /* we skip empty path components, like "x//y" since the FTP command
04277              CWD requires a parameter and a non-existent parameter a) doesn't
04278              work on many servers and b) has no effect on the others. */
04279           size_t len = slash_pos - cur_pos + absolute_dir;
04280           CURLcode result =
04281             Curl_urldecode(conn->data, cur_pos - absolute_dir, len,
04282                            &ftpc->dirs[ftpc->dirdepth], NULL,
04283                            TRUE);
04284           if(result) {
04285             free(ftpc->dirs[ftpc->dirdepth]);
04286             freedirs(ftpc);
04287             return result;
04288           }
04289         }
04290         else {
04291           cur_pos = slash_pos + 1; /* jump to the rest of the string */
04292           if(!ftpc->dirdepth) {
04293             /* path starts with a slash, add that as a directory */
04294             ftpc->dirs[ftpc->dirdepth] = strdup("/");
04295             if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
04296               failf(data, "no memory");
04297               freedirs(ftpc);
04298               return CURLE_OUT_OF_MEMORY;
04299             }
04300           }
04301           continue;
04302         }
04303 
04304         cur_pos = slash_pos + 1; /* jump to the rest of the string */
04305         if(++ftpc->dirdepth >= ftpc->diralloc) {
04306           /* enlarge array */
04307           char **bigger;
04308           ftpc->diralloc *= 2; /* double the size each time */
04309           bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
04310           if(!bigger) {
04311             freedirs(ftpc);
04312             return CURLE_OUT_OF_MEMORY;
04313           }
04314           ftpc->dirs = bigger;
04315         }
04316       }
04317     }
04318     filename = cur_pos;  /* the rest is the file name */
04319     break;
04320   } /* switch */
04321 
04322   if(filename && *filename) {
04323     CURLcode result =
04324       Curl_urldecode(conn->data, filename, 0,  &ftpc->file, NULL, TRUE);
04325 
04326     if(result) {
04327       freedirs(ftpc);
04328       return result;
04329     }
04330   }
04331   else
04332     ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
04333                        pointer */
04334 
04335   if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
04336     /* We need a file name when uploading. Return error! */
04337     failf(data, "Uploading to a URL without a file name!");
04338     return CURLE_URL_MALFORMAT;
04339   }
04340 
04341   ftpc->cwddone = FALSE; /* default to not done */
04342 
04343   if(ftpc->prevpath) {
04344     /* prevpath is "raw" so we convert the input path before we compare the
04345        strings */
04346     size_t dlen;
04347     char *path;
04348     CURLcode result =
04349       Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE);
04350     if(result) {
04351       freedirs(ftpc);
04352       return result;
04353     }
04354 
04355     dlen -= ftpc->file?strlen(ftpc->file):0;
04356     if((dlen == strlen(ftpc->prevpath)) &&
04357        !strncmp(path, ftpc->prevpath, dlen)) {
04358       infof(data, "Request has same path as previous transfer\n");
04359       ftpc->cwddone = TRUE;
04360     }
04361     free(path);
04362   }
04363 
04364   return CURLE_OK;
04365 }
04366 
04367 /* call this when the DO phase has completed */
04368 static CURLcode ftp_dophase_done(struct connectdata *conn,
04369                                  bool connected)
04370 {
04371   struct FTP *ftp = conn->data->req.protop;
04372   struct ftp_conn *ftpc = &conn->proto.ftpc;
04373 
04374   if(connected) {
04375     int completed;
04376     CURLcode result = ftp_do_more(conn, &completed);
04377 
04378     if(result) {
04379       close_secondarysocket(conn);
04380       return result;
04381     }
04382   }
04383 
04384   if(ftp->transfer != FTPTRANSFER_BODY)
04385     /* no data to transfer */
04386     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
04387   else if(!connected)
04388     /* since we didn't connect now, we want do_more to get called */
04389     conn->bits.do_more = TRUE;
04390 
04391   ftpc->ctl_valid = TRUE; /* seems good */
04392 
04393   return CURLE_OK;
04394 }
04395 
04396 /* called from multi.c while DOing */
04397 static CURLcode ftp_doing(struct connectdata *conn,
04398                           bool *dophase_done)
04399 {
04400   CURLcode result = ftp_multi_statemach(conn, dophase_done);
04401 
04402   if(result)
04403     DEBUGF(infof(conn->data, "DO phase failed\n"));
04404   else if(*dophase_done) {
04405     result = ftp_dophase_done(conn, FALSE /* not connected */);
04406 
04407     DEBUGF(infof(conn->data, "DO phase is complete2\n"));
04408   }
04409   return result;
04410 }
04411 
04412 /***********************************************************************
04413  *
04414  * ftp_regular_transfer()
04415  *
04416  * The input argument is already checked for validity.
04417  *
04418  * Performs all commands done before a regular transfer between a local and a
04419  * remote host.
04420  *
04421  * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
04422  * ftp_done() function without finding any major problem.
04423  */
04424 static
04425 CURLcode ftp_regular_transfer(struct connectdata *conn,
04426                               bool *dophase_done)
04427 {
04428   CURLcode result=CURLE_OK;
04429   bool connected=FALSE;
04430   struct Curl_easy *data = conn->data;
04431   struct ftp_conn *ftpc = &conn->proto.ftpc;
04432   data->req.size = -1; /* make sure this is unknown at this point */
04433 
04434   Curl_pgrsSetUploadCounter(data, 0);
04435   Curl_pgrsSetDownloadCounter(data, 0);
04436   Curl_pgrsSetUploadSize(data, -1);
04437   Curl_pgrsSetDownloadSize(data, -1);
04438 
04439   ftpc->ctl_valid = TRUE; /* starts good */
04440 
04441   result = ftp_perform(conn,
04442                        &connected, /* have we connected after PASV/PORT */
04443                        dophase_done); /* all commands in the DO-phase done? */
04444 
04445   if(!result) {
04446 
04447     if(!*dophase_done)
04448       /* the DO phase has not completed yet */
04449       return CURLE_OK;
04450 
04451     result = ftp_dophase_done(conn, connected);
04452 
04453     if(result)
04454       return result;
04455   }
04456   else
04457     freedirs(ftpc);
04458 
04459   return result;
04460 }
04461 
04462 static CURLcode ftp_setup_connection(struct connectdata *conn)
04463 {
04464   struct Curl_easy *data = conn->data;
04465   char *type;
04466   char command;
04467   struct FTP *ftp;
04468 
04469   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
04470     /* Unless we have asked to tunnel ftp operations through the proxy, we
04471        switch and use HTTP operations only */
04472 #ifndef CURL_DISABLE_HTTP
04473     if(conn->handler == &Curl_handler_ftp)
04474       conn->handler = &Curl_handler_ftp_proxy;
04475     else {
04476 #ifdef USE_SSL
04477       conn->handler = &Curl_handler_ftps_proxy;
04478 #else
04479       failf(data, "FTPS not supported!");
04480       return CURLE_UNSUPPORTED_PROTOCOL;
04481 #endif
04482     }
04483     /* set it up as a HTTP connection instead */
04484     return conn->handler->setup_connection(conn);
04485 #else
04486     failf(data, "FTP over http proxy requires HTTP support built-in!");
04487     return CURLE_UNSUPPORTED_PROTOCOL;
04488 #endif
04489   }
04490 
04491   conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
04492   if(NULL == ftp)
04493     return CURLE_OUT_OF_MEMORY;
04494 
04495   data->state.path++;   /* don't include the initial slash */
04496   data->state.slash_removed = TRUE; /* we've skipped the slash */
04497 
04498   /* FTP URLs support an extension like ";type=<typecode>" that
04499    * we'll try to get now! */
04500   type = strstr(data->state.path, ";type=");
04501 
04502   if(!type)
04503     type = strstr(conn->host.rawalloc, ";type=");
04504 
04505   if(type) {
04506     *type = 0;                     /* it was in the middle of the hostname */
04507     command = Curl_raw_toupper(type[6]);
04508     conn->bits.type_set = TRUE;
04509 
04510     switch(command) {
04511     case 'A': /* ASCII mode */
04512       data->set.prefer_ascii = TRUE;
04513       break;
04514 
04515     case 'D': /* directory mode */
04516       data->set.ftp_list_only = TRUE;
04517       break;
04518 
04519     case 'I': /* binary mode */
04520     default:
04521       /* switch off ASCII */
04522       data->set.prefer_ascii = FALSE;
04523       break;
04524     }
04525   }
04526 
04527   /* get some initial data into the ftp struct */
04528   ftp->bytecountp = &conn->data->req.bytecount;
04529   ftp->transfer = FTPTRANSFER_BODY;
04530   ftp->downloadsize = 0;
04531 
04532   /* No need to duplicate user+password, the connectdata struct won't change
04533      during a session, but we re-init them here since on subsequent inits
04534      since the conn struct may have changed or been replaced.
04535   */
04536   ftp->user = conn->user;
04537   ftp->passwd = conn->passwd;
04538   if(isBadFtpString(ftp->user))
04539     return CURLE_URL_MALFORMAT;
04540   if(isBadFtpString(ftp->passwd))
04541     return CURLE_URL_MALFORMAT;
04542 
04543   conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
04544 
04545   return CURLE_OK;
04546 }
04547 
04548 #endif /* CURL_DISABLE_FTP */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:02