File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / ftp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (4 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>