Annotation of embedaddon/curl/lib/ftp.c, revision 1.1.1.1

1.1       misho       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>