Lines Matching +full:ipv4 +full:- +full:multi +full:- +full:target
8 * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
79 #include "non-ascii.h"
221 if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) { in close_secondarysocket()
222 Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]); in close_secondarysocket()
223 conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; in close_secondarysocket()
225 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; in close_secondarysocket()
227 conn->bits.proxy_ssl_connected[SECONDARYSOCKET] = FALSE; in close_secondarysocket()
236 * This approach is not very elegant, it causes confusion and is error-prone.
245 if(ftpc->dirs) { in freedirs()
247 for(i = 0; i < ftpc->dirdepth; i++) { in freedirs()
248 free(ftpc->dirs[i]); in freedirs()
249 ftpc->dirs[i] = NULL; in freedirs()
251 free(ftpc->dirs); in freedirs()
252 ftpc->dirs = NULL; in freedirs()
253 ftpc->dirdepth = 0; in freedirs()
255 Curl_safefree(ftpc->file); in freedirs()
258 Curl_safefree(ftpc->newhost); in freedirs()
271 struct connectdata *conn = data->conn; in AcceptServerConnect()
272 curl_socket_t sock = conn->sock[SECONDARYSOCKET]; in AcceptServerConnect()
295 conn->bits.do_more = FALSE; in AcceptServerConnect()
297 conn->sock[SECONDARYSOCKET] = s; in AcceptServerConnect()
298 (void)curlx_nonblock(s, TRUE); /* enable non-blocking */ in AcceptServerConnect()
299 conn->bits.sock_accepted = TRUE; in AcceptServerConnect()
301 if(data->set.fsockopt) { in AcceptServerConnect()
306 error = data->set.fsockopt(data->set.sockopt_client, in AcceptServerConnect()
326 * The start time is stored in progress.t_acceptdata - as set with
336 if(data->set.accepttimeout > 0) in ftp_timeleft_accept()
337 timeout_ms = data->set.accepttimeout; in ftp_timeleft_accept()
349 timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata); in ftp_timeleft_accept()
352 return -1; in ftp_timeleft_accept()
370 struct connectdata *conn = data->conn; in ReceivedServerConnect()
371 curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET]; in ReceivedServerConnect()
372 curl_socket_t data_sock = conn->sock[SECONDARYSOCKET]; in ReceivedServerConnect()
373 struct ftp_conn *ftpc = &conn->proto.ftpc; in ReceivedServerConnect()
374 struct pingpong *pp = &ftpc->pp; in ReceivedServerConnect()
391 if(pp->cache_size && pp->cache && pp->cache[0] > '3') { in ReceivedServerConnect()
402 case -1: /* error */ in ReceivedServerConnect()
442 struct connectdata *conn = data->conn; in InitiateTransfer()
444 if(conn->bits.ftp_use_data_ssl) { in InitiateTransfer()
453 if(conn->proto.ftpc.state_saved == FTP_STOR) { in InitiateTransfer()
456 Curl_pgrsSetUploadSize(data, data->state.infilesize); in InitiateTransfer()
459 Curl_sndbufset(conn->sock[SECONDARYSOCKET]); in InitiateTransfer()
461 Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET); in InitiateTransfer()
466 conn->proto.ftpc.retr_size_saved, FALSE, -1); in InitiateTransfer()
469 conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */ in InitiateTransfer()
517 /* Add timeout to multi handle and break out of the loop */ in AllowServerConnect()
519 Curl_expire(data, data->set.accepttimeout > 0 ? in AllowServerConnect()
520 data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0); in AllowServerConnect()
527 /* macro to check for a three-digit ftp status code at the start of the
552 int *ftpcode, /* return the ftp-code if done */ in ftp_readresp()
560 struct connectdata *conn = data->conn; in ftp_readresp()
561 char * const buf = data->state.buffer; in ftp_readresp()
563 /* handle the security-oriented responses 6xx ***/ in ftp_readresp()
582 data->info.httpcode = code; in ftp_readresp()
595 infof(data, "We got a 421 - timeout!"); in ftp_readresp()
603 /* --- parse FTP server responses --- */
613 int *ftpcode) /* return the ftp-code */ in Curl_GetFTPResponse()
622 struct connectdata *conn = data->conn; in Curl_GetFTPResponse()
623 curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; in Curl_GetFTPResponse()
625 struct ftp_conn *ftpc = &conn->proto.ftpc; in Curl_GetFTPResponse()
626 struct pingpong *pp = &ftpc->pp; in Curl_GetFTPResponse()
662 * the cache wasn't good enough to continue we must not just busy-loop in Curl_GetFTPResponse()
667 if(pp->cache && (cache_skip < 2)) { in Curl_GetFTPResponse()
677 case -1: /* select() error, stop reading */ in Curl_GetFTPResponse()
695 if(!nread && pp->cache) in Curl_GetFTPResponse()
708 pp->pending_resp = FALSE; in Curl_GetFTPResponse()
762 struct connectdata *conn = data->conn; in _state()
763 struct ftp_conn *ftpc = &conn->proto.ftpc; in _state()
770 if(ftpc->state != newstate) in _state()
772 (void *)ftpc, lineno, ftp_state_names[ftpc->state], in _state()
777 ftpc->state = newstate; in _state()
784 &conn->proto.ftpc.pp, "USER %s", in ftp_state_user()
785 conn->user?conn->user:""); in ftp_state_user()
788 data->state.ftp_trying_alternative = FALSE; in ftp_state_user()
796 CURLcode result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PWD"); in ftp_state_pwd()
808 return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks); in ftp_getsock()
815 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_domore_getsock()
823 if(SOCKS_STATE(conn->cnnct.state)) in ftp_domore_getsock()
826 if(FTP_STOP == ftpc->state) { in ftp_domore_getsock()
832 socks[0] = conn->sock[FIRSTSOCKET]; in ftp_domore_getsock()
834 if(!data->set.ftp_use_port) { in ftp_domore_getsock()
840 if(conn->tempsock[i] != CURL_SOCKET_BAD) { in ftp_domore_getsock()
841 socks[s] = conn->tempsock[i]; in ftp_domore_getsock()
848 socks[1] = conn->sock[SECONDARYSOCKET]; in ftp_domore_getsock()
854 return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks); in ftp_domore_getsock()
867 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_cwd()
869 if(ftpc->cwddone) in ftp_state_cwd()
873 /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */ in ftp_state_cwd()
874 DEBUGASSERT((data->set.ftp_filemethod != FTPFILE_NOCWD) || in ftp_state_cwd()
875 !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')); in ftp_state_cwd()
877 ftpc->count2 = 0; /* count2 counts failed CWDs */ in ftp_state_cwd()
882 ftpc->count3 = (data->set.ftp_create_missing_dirs == 2)?1:0; in ftp_state_cwd()
884 if(conn->bits.reuse && ftpc->entrypath && in ftp_state_cwd()
886 !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) { in ftp_state_cwd()
887 /* This is a re-used connection. Since we change directory to where the in ftp_state_cwd()
890 ftpc->cwdcount = 0; /* we count this as the first path, then we add one in ftp_state_cwd()
891 for all upcoming ones in the ftp->dirs[] array */ in ftp_state_cwd()
892 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath); in ftp_state_cwd()
897 if(ftpc->dirdepth) { in ftp_state_cwd()
898 ftpc->cwdcount = 1; in ftp_state_cwd()
901 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", in ftp_state_cwd()
902 ftpc->dirs[ftpc->cwdcount -1]); in ftp_state_cwd()
925 struct connectdata *conn = data->conn; in ftp_state_use_port()
926 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_use_port()
943 char *string_ftpport = data->set.str[STRING_FTPPORT]; in ftp_state_use_port()
954 * (ipv4|ipv6|domain|interface)?(:port(-range)?)? in ftp_state_use_port()
957 if(data->set.str[STRING_FTPPORT] && in ftp_state_use_port()
958 (strlen(data->set.str[STRING_FTPPORT]) > 1)) { in ftp_state_use_port()
978 /* [ipv6]:port(-range) */ in ftp_state_use_port()
982 strncpy(addr, ip_start, ip_end - ip_start); in ftp_state_use_port()
993 /* either ipv6 or (ipv4|domain|interface):port(-range) */ in ftp_state_use_port()
1003 /* (ipv4|domain|interface):port(-range) */ in ftp_state_use_port()
1004 strncpy(addr, string_ftpport, ip_end - ip_start); in ftp_state_use_port()
1007 /* ipv4|interface */ in ftp_state_use_port()
1016 port_sep = strchr(port_start, '-'); in ftp_state_use_port()
1026 * :1234-1230 in ftp_state_use_port()
1027 * :-4711, in this case port_min is (unsigned)-1, in ftp_state_use_port()
1029 * but port_max = (unsigned)-1 in ftp_state_use_port()
1037 switch(Curl_if2ip(conn->ip_addr->ai_family, in ftp_state_use_port()
1038 Curl_ipv6_scope(conn->ip_addr->ai_addr), in ftp_state_use_port()
1039 conn->scope_id, addr, hbuf, sizeof(hbuf))) { in ftp_state_use_port()
1051 /* there was only a port(-range) given, default the host */ in ftp_state_use_port()
1053 } /* data->set.ftpport */ in ftp_state_use_port()
1060 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { in ftp_state_use_port()
1066 switch(sa->sa_family) { in ftp_state_use_port()
1069 r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); in ftp_state_use_port()
1073 r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); in ftp_state_use_port()
1087 res = h->addr; in ftp_state_use_port()
1108 for(ai = res; ai; ai = ai->ai_next) { in ftp_state_use_port()
1124 memcpy(sa, ai->ai_addr, ai->ai_addrlen); in ftp_state_use_port()
1125 sslen = ai->ai_addrlen; in ftp_state_use_port()
1128 if(sa->sa_family == AF_INET) in ftp_state_use_port()
1129 sa4->sin_port = htons(port); in ftp_state_use_port()
1132 sa6->sin6_port = htons(port); in ftp_state_use_port()
1142 infof(data, "bind(port=%hu) on non-local address failed: %s", port, in ftp_state_use_port()
1146 if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) { in ftp_state_use_port()
1202 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6) in ftp_state_use_port()
1205 conn->bits.ftp_use_eprt = TRUE; in ftp_state_use_port()
1210 if(!conn->bits.ftp_use_eprt && (EPRT == fcmd)) in ftp_state_use_port()
1214 if((PORT == fcmd) && sa->sa_family != AF_INET) in ftp_state_use_port()
1215 /* PORT is IPv4 only */ in ftp_state_use_port()
1218 switch(sa->sa_family) { in ftp_state_use_port()
1220 port = ntohs(sa4->sin_port); in ftp_state_use_port()
1224 port = ntohs(sa6->sin6_port); in ftp_state_use_port()
1240 result = Curl_pp_sendf(data, &ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd], in ftp_state_use_port()
1241 sa->sa_family == AF_INET?1:2, in ftp_state_use_port()
1248 ftpc->count1 = PORT; in ftp_state_use_port()
1257 char target[sizeof(myhost) + 20]; in ftp_state_use_port() local
1259 char *dest = target; in ftp_state_use_port()
1273 result = Curl_pp_sendf(data, &ftpc->pp, "%s %s", mode[fcmd], target); in ftp_state_use_port()
1287 ftpc->count1 = fcmd; in ftp_state_use_port()
1294 conn->sock[SECONDARYSOCKET] = portsock; in ftp_state_use_port()
1296 /* this tcpconnect assignment below is a hackish work-around to make the in ftp_state_use_port()
1297 multi interface with active FTP work - as it will not wait for a in ftp_state_use_port()
1301 server is done in a non-blocking way. Currently, it is still BLOCKING. in ftp_state_use_port()
1303 conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; in ftp_state_use_port()
1312 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_use_pasv()
1332 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6) in ftp_state_use_pasv()
1335 conn->bits.ftp_use_epsv = TRUE; in ftp_state_use_pasv()
1338 modeoff = conn->bits.ftp_use_epsv?0:1; in ftp_state_use_pasv()
1340 result = Curl_pp_sendf(data, &ftpc->pp, "%s", mode[modeoff]); in ftp_state_use_pasv()
1342 ftpc->count1 = modeoff; in ftp_state_use_pasv()
1352 * REST is the last command in the chain of commands when a "head"-like
1359 struct FTP *ftp = data->req.p.ftp; in ftp_state_prepare_transfer()
1360 struct connectdata *conn = data->conn; in ftp_state_prepare_transfer()
1362 if(ftp->transfer != PPTRANSFER_BODY) { in ftp_state_prepare_transfer()
1369 else if(data->set.ftp_use_port) { in ftp_state_prepare_transfer()
1375 if(data->set.ftp_use_pret) { in ftp_state_prepare_transfer()
1378 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_prepare_transfer()
1379 if(!conn->proto.ftpc.file) in ftp_state_prepare_transfer()
1380 result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s", in ftp_state_prepare_transfer()
1381 data->set.str[STRING_CUSTOMREQUEST]? in ftp_state_prepare_transfer()
1382 data->set.str[STRING_CUSTOMREQUEST]: in ftp_state_prepare_transfer()
1383 (data->state.list_only?"NLST":"LIST")); in ftp_state_prepare_transfer()
1384 else if(data->set.upload) in ftp_state_prepare_transfer()
1385 result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s", in ftp_state_prepare_transfer()
1386 conn->proto.ftpc.file); in ftp_state_prepare_transfer()
1388 result = Curl_pp_sendf(data, &ftpc->pp, "PRET RETR %s", in ftp_state_prepare_transfer()
1389 conn->proto.ftpc.file); in ftp_state_prepare_transfer()
1403 struct FTP *ftp = data->req.p.ftp; in ftp_state_rest()
1404 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_rest()
1406 if((ftp->transfer != PPTRANSFER_BODY) && ftpc->file) { in ftp_state_rest()
1407 /* if a "head"-like request is being made (on a file) */ in ftp_state_rest()
1411 result = Curl_pp_sendf(data, &ftpc->pp, "REST %d", 0); in ftp_state_rest()
1425 struct FTP *ftp = data->req.p.ftp; in ftp_state_size()
1426 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_size()
1428 if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) { in ftp_state_size()
1429 /* if a "head"-like request is being made (on a file) */ in ftp_state_size()
1431 /* we know ftpc->file is a valid pointer to a file name */ in ftp_state_size()
1432 result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); in ftp_state_size()
1445 struct FTP *ftp = data->req.p.ftp; in ftp_state_list()
1446 struct connectdata *conn = data->conn; in ftp_state_list()
1448 /* If this output is to be machine-parsed, the NLST command might be better in ftp_state_list()
1464 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) { in ftp_state_list()
1465 /* url-decode before evaluation: e.g. paths starting/ending with %2f */ in ftp_state_list()
1468 result = Curl_urldecode(data, ftp->path, 0, &rawPath, NULL, REJECT_CTRL); in ftp_state_list()
1476 size_t n = slashPos - rawPath; in ftp_state_list()
1488 data->set.str[STRING_CUSTOMREQUEST]? in ftp_state_list()
1489 data->set.str[STRING_CUSTOMREQUEST]: in ftp_state_list()
1490 (data->state.list_only?"NLST":"LIST"), in ftp_state_list()
1498 result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", cmd); in ftp_state_list()
1522 struct FTP *ftp = data->req.p.ftp; in ftp_state_type()
1523 struct connectdata *conn = data->conn; in ftp_state_type()
1524 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_type()
1529 if(data->set.opt_no_body && ftpc->file && in ftp_state_type()
1530 ftp_need_type(conn, data->state.prefer_ascii)) { in ftp_state_type()
1535 ftp->transfer = PPTRANSFER_INFO; in ftp_state_type()
1540 result = ftp_nb_type(data, conn, data->state.prefer_ascii, FTP_TYPE); in ftp_state_type()
1555 struct connectdata *conn = data->conn; in ftp_state_mdtm()
1556 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_mdtm()
1558 /* Requested time of file or time-depended transfer? */ in ftp_state_mdtm()
1559 if((data->set.get_filetime || data->set.timecondition) && ftpc->file) { in ftp_state_mdtm()
1561 /* we have requested to get the modified-time of the file, this is a white in ftp_state_mdtm()
1563 result = Curl_pp_sendf(data, &ftpc->pp, "MDTM %s", ftpc->file); in ftp_state_mdtm()
1580 struct connectdata *conn = data->conn; in ftp_state_ul_setup()
1581 struct FTP *ftp = data->req.p.ftp; in ftp_state_ul_setup()
1582 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_ul_setup()
1583 bool append = data->set.remote_append; in ftp_state_ul_setup()
1585 if((data->state.resume_from && !sizechecked) || in ftp_state_ul_setup()
1586 ((data->state.resume_from > 0) && sizechecked)) { in ftp_state_ul_setup()
1596 /* 3. pass file-size number of bytes in the source file */ in ftp_state_ul_setup()
1601 if(data->state.resume_from < 0) { in ftp_state_ul_setup()
1603 result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); in ftp_state_ul_setup()
1613 if(conn->seek_func) { in ftp_state_ul_setup()
1615 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, in ftp_state_ul_setup()
1629 (data->state.resume_from - passed > data->set.buffer_size) ? in ftp_state_ul_setup()
1630 (size_t)data->set.buffer_size : in ftp_state_ul_setup()
1631 curlx_sotouz(data->state.resume_from - passed); in ftp_state_ul_setup()
1634 data->state.fread_func(data->state.buffer, 1, readthisamountnow, in ftp_state_ul_setup()
1635 data->state.in); in ftp_state_ul_setup()
1639 /* this checks for greater-than only to make sure that the in ftp_state_ul_setup()
1644 } while(passed < data->state.resume_from); in ftp_state_ul_setup()
1647 if(data->state.infilesize>0) { in ftp_state_ul_setup()
1648 data->state.infilesize -= data->state.resume_from; in ftp_state_ul_setup()
1650 if(data->state.infilesize <= 0) { in ftp_state_ul_setup()
1654 Curl_setup_transfer(data, -1, -1, FALSE, -1); in ftp_state_ul_setup()
1656 /* Set ->transfer so that we won't get any error in in ftp_state_ul_setup()
1658 ftp->transfer = PPTRANSFER_NONE; in ftp_state_ul_setup()
1667 result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s", in ftp_state_ul_setup()
1668 ftpc->file); in ftp_state_ul_setup()
1680 struct FTP *ftp = data->req.p.ftp; in ftp_state_quote()
1681 struct connectdata *conn = data->conn; in ftp_state_quote()
1682 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_quote()
1689 item = data->set.quote; in ftp_state_quote()
1693 item = data->set.prequote; in ftp_state_quote()
1696 item = data->set.postquote; in ftp_state_quote()
1707 ftpc->count1 = 0; in ftp_state_quote()
1709 ftpc->count1++; in ftp_state_quote()
1715 while((i< ftpc->count1) && item) { in ftp_state_quote()
1716 item = item->next; in ftp_state_quote()
1720 char *cmd = item->data; in ftp_state_quote()
1723 ftpc->count2 = 1; /* the sent command is allowed to fail */ in ftp_state_quote()
1726 ftpc->count2 = 0; /* failure means cancel operation */ in ftp_state_quote()
1728 result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); in ftp_state_quote()
1744 if(ftp->transfer != PPTRANSFER_BODY) in ftp_state_quote()
1747 if(ftpc->known_filesize != -1) { in ftp_state_quote()
1748 Curl_pgrsSetDownloadSize(data, ftpc->known_filesize); in ftp_state_quote()
1749 result = ftp_state_retr(data, ftpc->known_filesize); in ftp_state_quote()
1752 if(data->set.ignorecl || data->state.prefer_ascii) { in ftp_state_quote()
1765 result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); in ftp_state_quote()
1770 result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file); in ftp_state_quote()
1795 if(conn->bits.ipv6 in ftp_epsv_disable()
1797 && !(conn->bits.tunnel_proxy || conn->bits.socksproxy) in ftp_epsv_disable()
1807 conn->bits.ftp_use_epsv = FALSE; in ftp_epsv_disable()
1808 data->state.errorbuf = FALSE; /* allow error message to get in ftp_epsv_disable()
1810 result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "PASV"); in ftp_epsv_disable()
1812 conn->proto.ftpc.count1++; in ftp_epsv_disable()
1827 if(conn->bits.tunnel_proxy || conn->bits.socksproxy) in control_address()
1828 return conn->host.name; in control_address()
1830 return conn->primary_ip; in control_address()
1836 struct connectdata *conn = data->conn; in ftp_state_pasv_resp()
1837 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_pasv_resp()
1842 char *str = &data->state.buffer[4]; /* start on the first letter */ in ftp_state_pasv_resp()
1845 Curl_safefree(ftpc->newhost); in ftp_state_pasv_resp()
1847 if((ftpc->count1 == 0) && in ftp_state_pasv_resp()
1877 ftpc->newport = (unsigned short)(num & 0xffff); in ftp_state_pasv_resp()
1878 ftpc->newhost = strdup(control_address(conn)); in ftp_state_pasv_resp()
1879 if(!ftpc->newhost) in ftp_state_pasv_resp()
1891 else if((ftpc->count1 == 1) && in ftp_state_pasv_resp()
1898 * Scan for a sequence of six comma-separated numbers and use them as in ftp_state_pasv_resp()
1901 * Found reply-strings include: in ftp_state_pasv_resp()
1916 failf(data, "Couldn't interpret the 227-response"); in ftp_state_pasv_resp()
1921 if(data->set.ftp_skip_ip) { in ftp_state_pasv_resp()
1924 infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead", in ftp_state_pasv_resp()
1926 conn->host.name); in ftp_state_pasv_resp()
1927 ftpc->newhost = strdup(control_address(conn)); in ftp_state_pasv_resp()
1930 ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); in ftp_state_pasv_resp()
1932 if(!ftpc->newhost) in ftp_state_pasv_resp()
1935 ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff); in ftp_state_pasv_resp()
1937 else if(ftpc->count1 == 0) { in ftp_state_pasv_resp()
1947 if(conn->bits.proxy) { in ftp_state_pasv_resp()
1953 const char * const host_name = conn->bits.socksproxy ? in ftp_state_pasv_resp()
1954 conn->socks_proxy.host.name : conn->http_proxy.host.name; in ftp_state_pasv_resp()
1955 rc = Curl_resolv(data, host_name, (int)conn->port, FALSE, &addr); in ftp_state_pasv_resp()
1962 (unsigned short)conn->port; /* we connect to the proxy's port */ in ftp_state_pasv_resp()
1973 DEBUGASSERT(ftpc->newhost); in ftp_state_pasv_resp()
1976 if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) { in ftp_state_pasv_resp()
1977 Curl_conninfo_remote(data, conn, conn->sock[FIRSTSOCKET]); in ftp_state_pasv_resp()
1978 Curl_safefree(ftpc->newhost); in ftp_state_pasv_resp()
1979 ftpc->newhost = strdup(control_address(conn)); in ftp_state_pasv_resp()
1980 if(!ftpc->newhost) in ftp_state_pasv_resp()
1984 rc = Curl_resolv(data, ftpc->newhost, ftpc->newport, FALSE, &addr); in ftp_state_pasv_resp()
1989 connectport = ftpc->newport; /* we connect to the remote port */ in ftp_state_pasv_resp()
1992 failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport); in ftp_state_pasv_resp()
1997 conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE; in ftp_state_pasv_resp()
2002 if(ftpc->count1 == 0 && ftpcode == 229) in ftp_state_pasv_resp()
2010 * When this is used from the multi interface, this might've returned with in ftp_state_pasv_resp()
2011 * the 'connected' set to FALSE and thus we are now awaiting a non-blocking in ftp_state_pasv_resp()
2015 if(data->set.verbose) in ftp_state_pasv_resp()
2017 ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport); in ftp_state_pasv_resp()
2021 Curl_safefree(conn->secondaryhostname); in ftp_state_pasv_resp()
2022 conn->secondary_port = ftpc->newport; in ftp_state_pasv_resp()
2023 conn->secondaryhostname = strdup(ftpc->newhost); in ftp_state_pasv_resp()
2024 if(!conn->secondaryhostname) in ftp_state_pasv_resp()
2027 conn->bits.do_more = TRUE; in ftp_state_pasv_resp()
2036 struct connectdata *conn = data->conn; in ftp_state_port_resp()
2037 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_port_resp()
2038 ftpport fcmd = (ftpport)ftpc->count1; in ftp_state_port_resp()
2048 conn->bits.ftp_use_eprt = FALSE; in ftp_state_port_resp()
2073 struct FTP *ftp = data->req.p.ftp; in ftp_state_mdtm_resp()
2074 struct connectdata *conn = data->conn; in ftp_state_mdtm_resp()
2075 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_mdtm_resp()
2083 if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d", in ftp_state_mdtm_resp()
2091 data->info.filetime = Curl_getdate_capped(timebuf); in ftp_state_mdtm_resp()
2096 we "emulate" a HTTP-style header in our output. */ in ftp_state_mdtm_resp()
2098 if(data->set.opt_no_body && in ftp_state_mdtm_resp()
2099 ftpc->file && in ftp_state_mdtm_resp()
2100 data->set.get_filetime && in ftp_state_mdtm_resp()
2101 (data->info.filetime >= 0) ) { in ftp_state_mdtm_resp()
2104 time_t filetime = data->info.filetime; in ftp_state_mdtm_resp()
2114 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", in ftp_state_mdtm_resp()
2115 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], in ftp_state_mdtm_resp()
2116 tm->tm_mday, in ftp_state_mdtm_resp()
2117 Curl_month[tm->tm_mon], in ftp_state_mdtm_resp()
2118 tm->tm_year + 1900, in ftp_state_mdtm_resp()
2119 tm->tm_hour, in ftp_state_mdtm_resp()
2120 tm->tm_min, in ftp_state_mdtm_resp()
2121 tm->tm_sec); in ftp_state_mdtm_resp()
2139 if(data->set.timecondition) { in ftp_state_mdtm_resp()
2140 if((data->info.filetime > 0) && (data->set.timevalue > 0)) { in ftp_state_mdtm_resp()
2141 switch(data->set.timecondition) { in ftp_state_mdtm_resp()
2144 if(data->info.filetime <= data->set.timevalue) { in ftp_state_mdtm_resp()
2146 ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */ in ftp_state_mdtm_resp()
2147 data->info.timecond = TRUE; in ftp_state_mdtm_resp()
2153 if(data->info.filetime > data->set.timevalue) { in ftp_state_mdtm_resp()
2155 ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */ in ftp_state_mdtm_resp()
2156 data->info.timecond = TRUE; in ftp_state_mdtm_resp()
2179 struct connectdata *conn = data->conn; in ftp_state_type_resp()
2208 struct FTP *ftp = data->req.p.ftp; in ftp_state_retr()
2209 struct connectdata *conn = data->conn; in ftp_state_retr()
2210 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_retr()
2212 if(data->set.max_filesize && (filesize > data->set.max_filesize)) { in ftp_state_retr()
2216 ftp->downloadsize = filesize; in ftp_state_retr()
2218 if(data->state.resume_from) { in ftp_state_retr()
2221 if(filesize == -1) { in ftp_state_retr()
2231 if(data->state.resume_from< 0) { in ftp_state_retr()
2233 if(filesize < -data->state.resume_from) { in ftp_state_retr()
2236 data->state.resume_from, filesize); in ftp_state_retr()
2240 ftp->downloadsize = -data->state.resume_from; in ftp_state_retr()
2242 data->state.resume_from = filesize - ftp->downloadsize; in ftp_state_retr()
2245 if(filesize < data->state.resume_from) { in ftp_state_retr()
2248 data->state.resume_from, filesize); in ftp_state_retr()
2252 ftp->downloadsize = filesize-data->state.resume_from; in ftp_state_retr()
2256 if(ftp->downloadsize == 0) { in ftp_state_retr()
2258 Curl_setup_transfer(data, -1, -1, FALSE, -1); in ftp_state_retr()
2261 /* Set ->transfer so that we won't get any error in ftp_done() in ftp_state_retr()
2263 ftp->transfer = PPTRANSFER_NONE; in ftp_state_retr()
2270 CURL_FORMAT_CURL_OFF_T, data->state.resume_from); in ftp_state_retr()
2272 result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T, in ftp_state_retr()
2273 data->state.resume_from); in ftp_state_retr()
2279 result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); in ftp_state_retr()
2292 curl_off_t filesize = -1; in ftp_state_size_resp()
2293 char *buf = data->state.buffer; in ftp_state_size_resp()
2304 fdigit--; in ftp_state_size_resp()
2326 if(-1 != filesize) { in ftp_state_size_resp()
2329 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); in ftp_state_size_resp()
2336 result = ftp_state_rest(data, data->conn); in ftp_state_size_resp()
2343 data->state.resume_from = filesize; in ftp_state_size_resp()
2356 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_rest_resp()
2363 char buffer[24]= { "Accept-ranges: bytes\r\n" }; in ftp_state_rest_resp()
2379 result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file); in ftp_state_rest_resp()
2393 struct connectdata *conn = data->conn; in ftp_state_stor_resp()
2402 conn->proto.ftpc.state_saved = instate; in ftp_state_stor_resp()
2405 if(data->set.ftp_use_port) { in ftp_state_stor_resp()
2415 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_stor_resp()
2417 ftpc->wait_data_conn = TRUE; in ftp_state_stor_resp()
2431 struct FTP *ftp = data->req.p.ftp; in ftp_state_get_resp()
2432 struct connectdata *conn = data->conn; in ftp_state_get_resp()
2453 curl_off_t size = -1; /* default unknown size */ in ftp_state_get_resp()
2457 * It appears that there are FTP-servers that return size 0 for files when in ftp_state_get_resp()
2466 !data->state.prefer_ascii && in ftp_state_get_resp()
2467 (ftp->downloadsize < 1)) { in ftp_state_get_resp()
2476 char *buf = data->state.buffer; in ftp_state_get_resp()
2479 long in = (long)(--bytes-buf); in ftp_state_get_resp()
2480 /* this is a hint there is size information in there! ;-) */ in ftp_state_get_resp()
2481 while(--in) { in ftp_state_get_resp()
2491 bytes--; in ftp_state_get_resp()
2501 else if(ftp->downloadsize > -1) in ftp_state_get_resp()
2502 size = ftp->downloadsize; in ftp_state_get_resp()
2504 if(size > data->req.maxdownload && data->req.maxdownload > 0) in ftp_state_get_resp()
2505 size = data->req.size = data->req.maxdownload; in ftp_state_get_resp()
2506 else if((instate != FTP_LIST) && (data->state.prefer_ascii)) in ftp_state_get_resp()
2507 size = -1; /* kludge for servers that understate ASCII mode file size */ in ftp_state_get_resp()
2510 data->req.maxdownload); in ftp_state_get_resp()
2517 conn->proto.ftpc.state_saved = instate; in ftp_state_get_resp()
2518 conn->proto.ftpc.retr_size_saved = size; in ftp_state_get_resp()
2520 if(data->set.ftp_use_port) { in ftp_state_get_resp()
2528 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_get_resp()
2531 ftpc->wait_data_conn = TRUE; in ftp_state_get_resp()
2540 ftp->transfer = PPTRANSFER_NONE; /* don't download anything */ in ftp_state_get_resp()
2558 struct connectdata *conn = data->conn; in ftp_state_loggedin()
2560 if(conn->bits.ftp_use_control_ssl) { in ftp_state_loggedin()
2563 The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: in ftp_state_loggedin()
2575 result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "PBSZ %d", 0); in ftp_state_loggedin()
2591 struct connectdata *conn = data->conn; in ftp_state_user_resp()
2592 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_state_user_resp()
2596 if((ftpcode == 331) && (ftpc->state == FTP_USER)) { in ftp_state_user_resp()
2599 result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s", in ftp_state_user_resp()
2600 conn->passwd?conn->passwd:""); in ftp_state_user_resp()
2610 if(data->set.str[STRING_FTP_ACCOUNT]) { in ftp_state_user_resp()
2611 result = Curl_pp_sendf(data, &ftpc->pp, "ACCT %s", in ftp_state_user_resp()
2612 data->set.str[STRING_FTP_ACCOUNT]); in ftp_state_user_resp()
2627 if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && in ftp_state_user_resp()
2628 !data->state.ftp_trying_alternative) { in ftp_state_user_resp()
2631 Curl_pp_sendf(data, &ftpc->pp, "%s", in ftp_state_user_resp()
2632 data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); in ftp_state_user_resp()
2634 data->state.ftp_trying_alternative = TRUE; in ftp_state_user_resp()
2666 curl_socket_t sock = conn->sock[FIRSTSOCKET]; in ftp_statemachine()
2668 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_statemachine()
2669 struct pingpong *pp = &ftpc->pp; in ftp_statemachine()
2673 if(pp->sendleft) in ftp_statemachine()
2682 switch(ftpc->state) { in ftp_statemachine()
2685 /* 230 User logged in - already! Take as 220 if TLS required. */ in ftp_statemachine()
2686 if(data->set.use_ssl <= CURLUSESSL_TRY || in ftp_statemachine()
2687 conn->bits.ftp_use_control_ssl) in ftp_statemachine()
2688 return ftp_state_user_resp(data, ftpcode, ftpc->state); in ftp_statemachine()
2691 failf(data, "Got a %03d ftp-server response when 220 was expected", in ftp_statemachine()
2698 if(data->set.krb) { in ftp_statemachine()
2705 Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); in ftp_statemachine()
2714 if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { in ftp_statemachine()
2718 ftpc->count3 = 0; in ftp_statemachine()
2719 switch(data->set.ftpsslauth) { in ftp_statemachine()
2722 ftpc->count2 = 1; /* add one to get next */ in ftp_statemachine()
2723 ftpc->count1 = 0; in ftp_statemachine()
2726 ftpc->count2 = -1; /* subtract one to get next */ in ftp_statemachine()
2727 ftpc->count1 = 1; in ftp_statemachine()
2731 (int)data->set.ftpsslauth); in ftp_statemachine()
2734 result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", in ftp_statemachine()
2735 ftpauth[ftpc->count1]); in ftp_statemachine()
2746 if(pp->cache_size) in ftp_statemachine()
2760 conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ in ftp_statemachine()
2761 conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ in ftp_statemachine()
2765 else if(ftpc->count3 < 1) { in ftp_statemachine()
2766 ftpc->count3++; in ftp_statemachine()
2767 ftpc->count1 += ftpc->count2; /* get next attempt */ in ftp_statemachine()
2768 result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", in ftp_statemachine()
2769 ftpauth[ftpc->count1]); in ftp_statemachine()
2773 if(data->set.use_ssl > CURLUSESSL_TRY) in ftp_statemachine()
2784 result = ftp_state_user_resp(data, ftpcode, ftpc->state); in ftp_statemachine()
2793 Curl_pp_sendf(data, &ftpc->pp, "PROT %c", in ftp_statemachine()
2794 data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); in ftp_statemachine()
2802 conn->bits.ftp_use_data_ssl = in ftp_statemachine()
2803 (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; in ftp_statemachine()
2806 else if(data->set.use_ssl > CURLUSESSL_CONTROL) in ftp_statemachine()
2810 if(data->set.ftp_ccc) { in ftp_statemachine()
2811 /* CCC - Clear Command Channel in ftp_statemachine()
2813 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); in ftp_statemachine()
2836 char *ptr = &data->state.buffer[4]; /* start on the first letter */ in ftp_statemachine()
2837 const size_t buf_size = data->set.buffer_size; in ftp_statemachine()
2846 257<space>[rubbish]"<directory-name>"<space><commentary> and the in ftp_statemachine()
2850 double-quotes should be escaped by double-quotes (the in ftp_statemachine()
2851 "quote-doubling" convention). in ftp_statemachine()
2854 /* scan for the first double-quote for non-standard responses */ in ftp_statemachine()
2855 while(ptr < &data->state.buffer[buf_size] in ftp_statemachine()
2866 /* "quote-doubling" */ in ftp_statemachine()
2881 *store = '\0'; /* null-terminate */ in ftp_statemachine()
2885 does not start with a '/'), we probably need some server-dependent in ftp_statemachine()
2896 if(!ftpc->server_os && dir[0] != '/') { in ftp_statemachine()
2897 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); in ftp_statemachine()
2902 Curl_safefree(ftpc->entrypath); in ftp_statemachine()
2903 ftpc->entrypath = dir; /* remember this */ in ftp_statemachine()
2904 infof(data, "Entry path is '%s'", ftpc->entrypath); in ftp_statemachine()
2906 data->state.most_recent_ftp_entrypath = ftpc->entrypath; in ftp_statemachine()
2911 Curl_safefree(ftpc->entrypath); in ftp_statemachine()
2912 ftpc->entrypath = dir; /* remember this */ in ftp_statemachine()
2913 infof(data, "Entry path is '%s'", ftpc->entrypath); in ftp_statemachine()
2915 data->state.most_recent_ftp_entrypath = ftpc->entrypath; in ftp_statemachine()
2929 char *ptr = &data->state.buffer[4]; /* start on the first letter */ in ftp_statemachine()
2938 215<space><OS-name><space><commentary> in ftp_statemachine()
2944 *store = '\0'; /* null-terminate */ in ftp_statemachine()
2950 result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); in ftp_statemachine()
2955 /* remember target server OS */ in ftp_statemachine()
2956 Curl_safefree(ftpc->server_os); in ftp_statemachine()
2957 ftpc->server_os = os; in ftp_statemachine()
2961 /* Nothing special for the target server. */ in ftp_statemachine()
2962 /* remember target server OS */ in ftp_statemachine()
2963 Curl_safefree(ftpc->server_os); in ftp_statemachine()
2964 ftpc->server_os = os; in ftp_statemachine()
2989 if((ftpcode >= 400) && !ftpc->count2) { in ftp_statemachine()
2995 result = ftp_state_quote(data, FALSE, ftpc->state); in ftp_statemachine()
3001 if(data->set.ftp_create_missing_dirs && in ftp_statemachine()
3002 ftpc->cwdcount && !ftpc->count2) { in ftp_statemachine()
3004 ftpc->count2++; /* counter to prevent CWD-MKD loops */ in ftp_statemachine()
3005 result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", in ftp_statemachine()
3006 ftpc->dirs[ftpc->cwdcount - 1]); in ftp_statemachine()
3013 ftpc->cwdfail = TRUE; /* don't remember this path as we failed in ftp_statemachine()
3020 ftpc->count2 = 0; in ftp_statemachine()
3021 if(++ftpc->cwdcount <= ftpc->dirdepth) in ftp_statemachine()
3023 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", in ftp_statemachine()
3024 ftpc->dirs[ftpc->cwdcount - 1]); in ftp_statemachine()
3031 if((ftpcode/100 != 2) && !ftpc->count3--) { in ftp_statemachine()
3039 result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", in ftp_statemachine()
3040 ftpc->dirs[ftpc->cwdcount - 1]); in ftp_statemachine()
3052 result = ftp_state_type_resp(data, ftpcode, ftpc->state); in ftp_statemachine()
3058 result = ftp_state_size_resp(data, ftpcode, ftpc->state); in ftp_statemachine()
3063 result = ftp_state_rest_resp(data, conn, ftpcode, ftpc->state); in ftp_statemachine()
3085 result = ftp_state_get_resp(data, ftpcode, ftpc->state); in ftp_statemachine()
3089 result = ftp_state_stor_resp(data, ftpcode, ftpc->state); in ftp_statemachine()
3105 /* called repeatedly until done from multi.c */
3109 struct connectdata *conn = data->conn; in ftp_multi_statemach()
3110 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_multi_statemach()
3111 CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE); in ftp_multi_statemach()
3116 *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; in ftp_multi_statemach()
3124 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_block_statemach()
3125 struct pingpong *pp = &ftpc->pp; in ftp_block_statemach()
3128 while(ftpc->state != FTP_STOP) { in ftp_block_statemach()
3141 * The variable 'done' points to will be TRUE if the protocol-layer connect
3149 struct connectdata *conn = data->conn; in ftp_connect()
3150 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_connect()
3151 struct pingpong *pp = &ftpc->pp; in ftp_connect()
3160 if(conn->handler->flags & PROTOPT_SSL) { in ftp_connect()
3165 conn->bits.ftp_use_control_ssl = TRUE; in ftp_connect()
3192 struct connectdata *conn = data->conn; in ftp_done()
3193 struct FTP *ftp = data->req.p.ftp; in ftp_done()
3194 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_done()
3195 struct pingpong *pp = &ftpc->pp; in ftp_done()
3220 /* fall-through */ in ftp_done()
3230 ftpc->ctl_valid = FALSE; in ftp_done()
3231 ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the in ftp_done()
3238 if(data->state.wildcardmatch) { in ftp_done()
3239 if(data->set.chunk_end && ftpc->file) { in ftp_done()
3241 data->set.chunk_end(data->wildcard.customptr); in ftp_done()
3244 ftpc->known_filesize = -1; in ftp_done()
3248 /* get the url-decoded "raw" path */ in ftp_done()
3249 result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, in ftp_done()
3254 ftpc->ctl_valid = FALSE; /* mark control connection as bad */ in ftp_done()
3256 free(ftpc->prevpath); in ftp_done()
3257 ftpc->prevpath = NULL; /* no path remembering */ in ftp_done()
3260 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) in ftp_done()
3261 free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */ in ftp_done()
3263 free(ftpc->prevpath); in ftp_done()
3265 if(!ftpc->cwdfail) { in ftp_done()
3266 if(data->set.ftp_filemethod == FTPFILE_NOCWD) in ftp_done()
3269 pathLen -= ftpc->file?strlen(ftpc->file):0; /* file is url-decoded */ in ftp_done()
3272 ftpc->prevpath = rawPath; in ftp_done()
3276 ftpc->prevpath = NULL; /* no path */ in ftp_done()
3280 if(ftpc->prevpath) in ftp_done()
3281 infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath); in ftp_done()
3290 shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */ in ftp_done()
3293 if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { in ftp_done()
3294 if(!result && ftpc->dont_check && data->req.maxdownload > 0) { in ftp_done()
3300 ftpc->ctl_valid = FALSE; /* mark control connection as bad */ in ftp_done()
3305 if(conn->ssl[SECONDARYSOCKET].use) { in ftp_done()
3316 if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid && in ftp_done()
3317 pp->pending_resp && !premature) { in ftp_done()
3324 timediff_t old_time = pp->response_time; in ftp_done()
3326 pp->response_time = 60*1000; /* give it only a minute for now */ in ftp_done()
3327 pp->response = Curl_now(); /* timeout relative now */ in ftp_done()
3331 pp->response_time = old_time; /* set this back to previous value */ in ftp_done()
3335 ftpc->ctl_valid = FALSE; /* mark control connection as bad */ in ftp_done()
3340 Curl_safefree(ftp->pathalloc); in ftp_done()
3344 if(ftpc->dont_check && data->req.maxdownload > 0) { in ftp_done()
3352 if(!ftpc->dont_check) { in ftp_done()
3374 else if(data->set.upload) { in ftp_done()
3375 if((-1 != data->state.infilesize) && in ftp_done()
3376 (data->state.infilesize != data->req.writebytecount) && in ftp_done()
3377 !data->set.crlf && in ftp_done()
3378 (ftp->transfer == PPTRANSFER_BODY)) { in ftp_done()
3381 data->req.bytecount, data->state.infilesize); in ftp_done()
3386 if((-1 != data->req.size) && in ftp_done()
3387 (data->req.size != data->req.bytecount) && in ftp_done()
3393 ((data->req.size + data->state.crlf_conversions) != in ftp_done()
3394 data->req.bytecount) && in ftp_done()
3396 (data->req.maxdownload != data->req.bytecount)) { in ftp_done()
3398 " bytes", data->req.bytecount); in ftp_done()
3401 else if(!ftpc->dont_check && in ftp_done()
3402 !data->req.bytecount && in ftp_done()
3403 (data->req.size>0)) { in ftp_done()
3410 ftp->transfer = PPTRANSFER_BODY; in ftp_done()
3411 ftpc->dont_check = FALSE; in ftp_done()
3413 /* Send any post-transfer QUOTE strings? */ in ftp_done()
3414 if(!status && !result && !premature && data->set.postquote) in ftp_done()
3415 result = ftp_sendquote(data, conn, data->set.postquote); in ftp_done()
3416 Curl_safefree(ftp->pathalloc); in ftp_done()
3435 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_sendquote()
3436 struct pingpong *pp = &ftpc->pp; in ftp_sendquote()
3440 if(item->data) { in ftp_sendquote()
3442 char *cmd = item->data; in ftp_sendquote()
3457 result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd); in ftp_sendquote()
3459 pp->response = Curl_now(); /* timeout relative now */ in ftp_sendquote()
3471 item = item->next; in ftp_sendquote()
3486 return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I'); in ftp_need_type()
3501 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_nb_type()
3505 if(ftpc->transfertype == want) { in ftp_nb_type()
3510 result = Curl_pp_sendf(data, &ftpc->pp, "TYPE %c", want); in ftp_nb_type()
3515 ftpc->transfertype = want; in ftp_nb_type()
3548 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
3555 struct connectdata *conn = data->conn; in ftp_do_more()
3556 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_do_more()
3562 struct FTP *ftp = data->req.p.ftp; in ftp_do_more()
3565 if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { in ftp_do_more()
3578 DEBUGF(infof(data, "DO-MORE connected phase starts")); in ftp_do_more()
3581 if(result && (ftpc->count1 == 0)) { in ftp_do_more()
3582 *completep = -1; /* go back to DOING please */ in ftp_do_more()
3598 if(conn->bits.tunnel_proxy && conn->bits.httpproxy && in ftp_do_more()
3603 if(ftpc->state) { in ftp_do_more()
3612 if(result || !ftpc->wait_data_conn) in ftp_do_more()
3616 TRUE but so is ftpc->wait_data_conn, which says we need to wait for the in ftp_do_more()
3621 if(ftp->transfer <= PPTRANSFER_INFO) { in ftp_do_more()
3625 if(ftpc->wait_data_conn == TRUE) { in ftp_do_more()
3635 ftpc->wait_data_conn = FALSE; in ftp_do_more()
3646 else if(data->set.upload) { in ftp_do_more()
3647 result = ftp_nb_type(data, conn, data->state.prefer_ascii, in ftp_do_more()
3653 if(ftpc->wait_data_conn) in ftp_do_more()
3655 TRUE but so is ftpc->wait_data_conn, which says we need to wait for in ftp_do_more()
3663 ftp->downloadsize = -1; /* unknown as of yet */ in ftp_do_more()
3667 if(result == CURLE_OK && data->req.maxdownload >= 0) { in ftp_do_more()
3669 ftpc->dont_check = TRUE; in ftp_do_more()
3674 else if(data->state.list_only || !ftpc->file) { in ftp_do_more()
3680 if(ftp->transfer == PPTRANSFER_BODY) { in ftp_do_more()
3688 result = ftp_nb_type(data, conn, data->state.prefer_ascii, in ftp_do_more()
3701 Curl_setup_transfer(data, -1, -1, FALSE, -1); in ftp_do_more()
3703 if(!ftpc->wait_data_conn) { in ftp_do_more()
3706 DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result)); in ftp_do_more()
3729 struct connectdata *conn = data->conn; in ftp_perform()
3733 if(data->set.opt_no_body) { in ftp_perform()
3735 struct FTP *ftp = data->req.p.ftp; in ftp_perform()
3736 ftp->transfer = PPTRANSFER_INFO; in ftp_perform()
3746 /* run the state-machine */ in ftp_perform()
3749 *connected = conn->bits.tcpconnect[SECONDARYSOCKET]; in ftp_perform()
3762 if(ftpwc && ftpwc->parser) in wc_data_dtor()
3763 Curl_ftp_parselist_data_free(&ftpwc->parser); in wc_data_dtor()
3770 struct FTP *ftp = data->req.p.ftp; in init_wc_data()
3771 char *path = ftp->path; in init_wc_data()
3772 struct WildcardData *wildcard = &(data->wildcard); in init_wc_data()
3776 last_slash = strrchr(ftp->path, '/'); in init_wc_data()
3780 wildcard->state = CURLWC_CLEAN; in init_wc_data()
3784 wildcard->pattern = strdup(last_slash); in init_wc_data()
3785 if(!wildcard->pattern) in init_wc_data()
3791 wildcard->pattern = strdup(path); in init_wc_data()
3792 if(!wildcard->pattern) in init_wc_data()
3797 wildcard->state = CURLWC_CLEAN; in init_wc_data()
3814 ftpwc->parser = Curl_ftp_parselist_data_alloc(); in init_wc_data()
3815 if(!ftpwc->parser) { in init_wc_data()
3820 wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */ in init_wc_data()
3821 wildcard->dtor = wc_data_dtor; in init_wc_data()
3824 if(data->set.ftp_filemethod == FTPFILE_NOCWD) in init_wc_data()
3825 data->set.ftp_filemethod = FTPFILE_MULTICWD; in init_wc_data()
3833 wildcard->path = strdup(ftp->path); in init_wc_data()
3834 if(!wildcard->path) { in init_wc_data()
3840 ftpwc->backup.write_function = data->set.fwrite_func; in init_wc_data()
3842 data->set.fwrite_func = Curl_ftp_parselist; in init_wc_data()
3844 ftpwc->backup.file_descriptor = data->set.out; in init_wc_data()
3846 data->set.out = data; in init_wc_data()
3848 infof(data, "Wildcard - Parsing started"); in init_wc_data()
3853 Curl_ftp_parselist_data_free(&ftpwc->parser); in init_wc_data()
3856 Curl_safefree(wildcard->pattern); in init_wc_data()
3857 wildcard->dtor = ZERO_NULL; in init_wc_data()
3858 wildcard->protdata = NULL; in init_wc_data()
3864 struct WildcardData * const wildcard = &(data->wildcard); in wc_statemach()
3865 struct connectdata *conn = data->conn; in wc_statemach()
3869 switch(wildcard->state) { in wc_statemach()
3872 if(wildcard->state == CURLWC_CLEAN) in wc_statemach()
3875 wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; in wc_statemach()
3881 struct ftp_wc *ftpwc = wildcard->protdata; in wc_statemach()
3882 data->set.fwrite_func = ftpwc->backup.write_function; in wc_statemach()
3883 data->set.out = ftpwc->backup.file_descriptor; in wc_statemach()
3884 ftpwc->backup.write_function = ZERO_NULL; in wc_statemach()
3885 ftpwc->backup.file_descriptor = NULL; in wc_statemach()
3886 wildcard->state = CURLWC_DOWNLOADING; in wc_statemach()
3888 if(Curl_ftp_parselist_geterror(ftpwc->parser)) { in wc_statemach()
3890 wildcard->state = CURLWC_CLEAN; in wc_statemach()
3893 if(wildcard->filelist.size == 0) { in wc_statemach()
3895 wildcard->state = CURLWC_CLEAN; in wc_statemach()
3903 struct ftp_conn *ftpc = &conn->proto.ftpc; in wc_statemach()
3904 struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; in wc_statemach()
3905 struct FTP *ftp = data->req.p.ftp; in wc_statemach()
3907 char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); in wc_statemach()
3911 /* switch default ftp->path and tmp_path */ in wc_statemach()
3912 free(ftp->pathalloc); in wc_statemach()
3913 ftp->pathalloc = ftp->path = tmp_path; in wc_statemach()
3915 infof(data, "Wildcard - START of \"%s\"", finfo->filename); in wc_statemach()
3916 if(data->set.chunk_bgn) { in wc_statemach()
3919 userresponse = data->set.chunk_bgn( in wc_statemach()
3920 finfo, wildcard->customptr, (int)wildcard->filelist.size); in wc_statemach()
3924 infof(data, "Wildcard - \"%s\" skipped by user", in wc_statemach()
3925 finfo->filename); in wc_statemach()
3926 wildcard->state = CURLWC_SKIP; in wc_statemach()
3933 if(finfo->filetype != CURLFILETYPE_FILE) { in wc_statemach()
3934 wildcard->state = CURLWC_SKIP; in wc_statemach()
3938 if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE) in wc_statemach()
3939 ftpc->known_filesize = finfo->size; in wc_statemach()
3946 Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); in wc_statemach()
3948 if(wildcard->filelist.size == 0) { /* remains only one file to down. */ in wc_statemach()
3949 wildcard->state = CURLWC_CLEAN; in wc_statemach()
3958 if(data->set.chunk_end) { in wc_statemach()
3960 data->set.chunk_end(data->wildcard.customptr); in wc_statemach()
3963 Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); in wc_statemach()
3964 wildcard->state = (wildcard->filelist.size == 0) ? in wc_statemach()
3970 struct ftp_wc *ftpwc = wildcard->protdata; in wc_statemach()
3973 result = Curl_ftp_parselist_geterror(ftpwc->parser); in wc_statemach()
3975 wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE; in wc_statemach()
3982 if(wildcard->dtor) in wc_statemach()
3983 wildcard->dtor(wildcard->protdata); in wc_statemach()
4002 struct connectdata *conn = data->conn; in ftp_do()
4003 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_do()
4006 ftpc->wait_data_conn = FALSE; /* default to no such wait */ in ftp_do()
4008 if(data->state.wildcardmatch) { in ftp_do()
4010 if(data->wildcard.state == CURLWC_SKIP || in ftp_do()
4011 data->wildcard.state == CURLWC_DONE) { in ftp_do()
4043 if(conn->proto.ftpc.ctl_valid) { in ftp_quit()
4044 result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "QUIT"); in ftp_quit()
4048 conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */ in ftp_quit()
4066 * Disconnect from an FTP server. Cleanup protocol-specific per-connection
4073 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_disconnect()
4074 struct pingpong *pp = &ftpc->pp; in ftp_disconnect()
4080 ftp_quit() will check the state of ftp->ctl_valid. If it's ok it in ftp_disconnect()
4084 ftpc->ctl_valid = FALSE; in ftp_disconnect()
4089 if(ftpc->entrypath) { in ftp_disconnect()
4090 if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) { in ftp_disconnect()
4091 data->state.most_recent_ftp_entrypath = NULL; in ftp_disconnect()
4093 Curl_safefree(ftpc->entrypath); in ftp_disconnect()
4097 Curl_safefree(ftpc->prevpath); in ftp_disconnect()
4098 Curl_safefree(ftpc->server_os); in ftp_disconnect()
4115 struct FTP *ftp = data->req.p.ftp; in ftp_parse_url_path()
4116 struct connectdata *conn = data->conn; in ftp_parse_url_path()
4117 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_parse_url_path()
4121 char *rawPath = NULL; /* url-decoded "raw" path */ in ftp_parse_url_path()
4124 ftpc->ctl_valid = FALSE; in ftp_parse_url_path()
4125 ftpc->cwdfail = FALSE; in ftp_parse_url_path()
4127 /* url-decode ftp path before further evaluation */ in ftp_parse_url_path()
4128 result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL); in ftp_parse_url_path()
4132 switch(data->set.ftp_filemethod) { in ftp_parse_url_path()
4133 case FTPFILE_NOCWD: /* fastest, but less standard-compliant */ in ftp_parse_url_path()
4135 if((pathLen > 0) && (rawPath[pathLen - 1] != '/')) in ftp_parse_url_path()
4138 else: ftpc->file is not used anywhere other than for operations on in ftp_parse_url_path()
4149 size_t dirlen = slashPos - rawPath; in ftp_parse_url_path()
4153 ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); in ftp_parse_url_path()
4154 if(!ftpc->dirs) { in ftp_parse_url_path()
4159 ftpc->dirs[0] = calloc(1, dirlen + 1); in ftp_parse_url_path()
4160 if(!ftpc->dirs[0]) { in ftp_parse_url_path()
4165 strncpy(ftpc->dirs[0], rawPath, dirlen); in ftp_parse_url_path()
4166 ftpc->dirdepth = 1; /* we consider it to be a single dir */ in ftp_parse_url_path()
4185 ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0])); in ftp_parse_url_path()
4186 if(!ftpc->dirs) { in ftp_parse_url_path()
4193 size_t compLen = slashPos - curPos; in ftp_parse_url_path()
4196 if((compLen == 0) && (ftpc->dirdepth == 0)) in ftp_parse_url_path()
4200 CWD requires a parameter and a non-existent parameter a) doesn't in ftp_parse_url_path()
4209 ftpc->dirs[ftpc->dirdepth++] = comp; in ftp_parse_url_path()
4214 DEBUGASSERT(ftpc->dirdepth <= dirAlloc); in ftp_parse_url_path()
4221 ftpc->file = strdup(fileName); in ftp_parse_url_path()
4223 ftpc->file = NULL; /* instead of point to a zero byte, in ftp_parse_url_path()
4226 if(data->set.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) { in ftp_parse_url_path()
4233 ftpc->cwddone = FALSE; /* default to not done */ in ftp_parse_url_path()
4235 if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) in ftp_parse_url_path()
4236 ftpc->cwddone = TRUE; /* skip CWD for absolute paths */ in ftp_parse_url_path()
4238 const char *oldPath = conn->bits.reuse ? ftpc->prevpath : ""; in ftp_parse_url_path()
4241 if(data->set.ftp_filemethod == FTPFILE_NOCWD) in ftp_parse_url_path()
4244 n -= ftpc->file?strlen(ftpc->file):0; in ftp_parse_url_path()
4248 ftpc->cwddone = TRUE; in ftp_parse_url_path()
4260 struct connectdata *conn = data->conn; in ftp_dophase_done()
4261 struct FTP *ftp = data->req.p.ftp; in ftp_dophase_done()
4262 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_dophase_done()
4274 if(ftp->transfer != PPTRANSFER_BODY) in ftp_dophase_done()
4276 Curl_setup_transfer(data, -1, -1, FALSE, -1); in ftp_dophase_done()
4279 conn->bits.do_more = TRUE; in ftp_dophase_done()
4281 ftpc->ctl_valid = TRUE; /* seems good */ in ftp_dophase_done()
4286 /* called from multi.c while DOing */
4311 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
4320 struct connectdata *conn = data->conn; in ftp_regular_transfer()
4321 struct ftp_conn *ftpc = &conn->proto.ftpc; in ftp_regular_transfer()
4322 data->req.size = -1; /* make sure this is unknown at this point */ in ftp_regular_transfer()
4326 Curl_pgrsSetUploadSize(data, -1); in ftp_regular_transfer()
4327 Curl_pgrsSetDownloadSize(data, -1); in ftp_regular_transfer()
4329 ftpc->ctl_valid = TRUE; /* starts good */ in ftp_regular_transfer()
4333 dophase_done); /* all commands in the DO-phase done? */ in ftp_regular_transfer()
4358 data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1); in ftp_setup_connection()
4362 ftp->path = &data->state.up.path[1]; /* don't include the initial slash */ in ftp_setup_connection()
4366 type = strstr(ftp->path, ";type="); in ftp_setup_connection()
4369 type = strstr(conn->host.rawalloc, ";type="); in ftp_setup_connection()
4378 data->state.prefer_ascii = TRUE; in ftp_setup_connection()
4382 data->state.list_only = TRUE; in ftp_setup_connection()
4388 data->state.prefer_ascii = FALSE; in ftp_setup_connection()
4394 ftp->transfer = PPTRANSFER_BODY; in ftp_setup_connection()
4395 ftp->downloadsize = 0; in ftp_setup_connection()
4396 conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ in ftp_setup_connection()