001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.net.ftp; 018import java.io.BufferedInputStream; 019import java.io.BufferedOutputStream; 020import java.io.BufferedReader; 021import java.io.BufferedWriter; 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.InputStreamReader; 025import java.io.OutputStream; 026import java.io.OutputStreamWriter; 027import java.io.Reader; 028import java.net.Inet6Address; 029import java.net.InetAddress; 030import java.net.InetSocketAddress; 031import java.net.ServerSocket; 032import java.net.Socket; 033import java.net.SocketException; 034import java.net.SocketTimeoutException; 035import java.net.UnknownHostException; 036import java.util.ArrayList; 037import java.util.HashMap; 038import java.util.HashSet; 039import java.util.Locale; 040import java.util.Properties; 041import java.util.Random; 042import java.util.Set; 043 044import org.apache.commons.net.MalformedServerReplyException; 045import org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory; 046import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory; 047import org.apache.commons.net.ftp.parser.MLSxEntryParser; 048import org.apache.commons.net.io.CRLFLineReader; 049import org.apache.commons.net.io.CopyStreamAdapter; 050import org.apache.commons.net.io.CopyStreamEvent; 051import org.apache.commons.net.io.CopyStreamListener; 052import org.apache.commons.net.io.FromNetASCIIInputStream; 053import org.apache.commons.net.io.ToNetASCIIOutputStream; 054import org.apache.commons.net.io.Util; 055 056/** 057 * FTPClient encapsulates all the functionality necessary to store and 058 * retrieve files from an FTP server. This class takes care of all 059 * low level details of interacting with an FTP server and provides 060 * a convenient higher level interface. As with all classes derived 061 * from {@link org.apache.commons.net.SocketClient}, 062 * you must first connect to the server with 063 * {@link org.apache.commons.net.SocketClient#connect connect } 064 * before doing anything, and finally 065 * {@link org.apache.commons.net.SocketClient#disconnect disconnect } 066 * after you're completely finished interacting with the server. 067 * Then you need to check the FTP reply code to see if the connection 068 * was successful. For example: 069 * <pre> 070 * FTPClient ftp = new FTPClient(); 071 * FTPClientConfig config = new FTPClientConfig(); 072 * config.setXXX(YYY); // change required options 073 * // for example config.setServerTimeZoneId("Pacific/Pitcairn") 074 * ftp.configure(config ); 075 * boolean error = false; 076 * try { 077 * int reply; 078 * String server = "ftp.example.com"; 079 * ftp.connect(server); 080 * System.out.println("Connected to " + server + "."); 081 * System.out.print(ftp.getReplyString()); 082 * 083 * // After connection attempt, you should check the reply code to verify 084 * // success. 085 * reply = ftp.getReplyCode(); 086 * 087 * if(!FTPReply.isPositiveCompletion(reply)) { 088 * ftp.disconnect(); 089 * System.err.println("FTP server refused connection."); 090 * System.exit(1); 091 * } 092 * ... // transfer files 093 * ftp.logout(); 094 * } catch(IOException e) { 095 * error = true; 096 * e.printStackTrace(); 097 * } finally { 098 * if(ftp.isConnected()) { 099 * try { 100 * ftp.disconnect(); 101 * } catch(IOException ioe) { 102 * // do nothing 103 * } 104 * } 105 * System.exit(error ? 1 : 0); 106 * } 107 * </pre> 108 * <p> 109 * Immediately after connecting is the only real time you need to check the 110 * reply code (because connect is of type void). The convention for all the 111 * FTP command methods in FTPClient is such that they either return a 112 * boolean value or some other value. 113 * The boolean methods return true on a successful completion reply from 114 * the FTP server and false on a reply resulting in an error condition or 115 * failure. The methods returning a value other than boolean return a value 116 * containing the higher level data produced by the FTP command, or null if a 117 * reply resulted in an error condition or failure. If you want to access 118 * the exact FTP reply code causing a success or failure, you must call 119 * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode } after 120 * a success or failure. 121 * <p> 122 * The default settings for FTPClient are for it to use 123 * <code> FTP.ASCII_FILE_TYPE </code>, 124 * <code> FTP.NON_PRINT_TEXT_FORMAT </code>, 125 * <code> FTP.STREAM_TRANSFER_MODE </code>, and 126 * <code> FTP.FILE_STRUCTURE </code>. The only file types directly supported 127 * are <code> FTP.ASCII_FILE_TYPE </code> and 128 * <code> FTP.BINARY_FILE_TYPE </code>. Because there are at least 4 129 * different EBCDIC encodings, we have opted not to provide direct support 130 * for EBCDIC. To transfer EBCDIC and other unsupported file types you 131 * must create your own filter InputStreams and OutputStreams and wrap 132 * them around the streams returned or required by the FTPClient methods. 133 * FTPClient uses the {@link ToNetASCIIOutputStream NetASCII} 134 * filter streams to provide transparent handling of ASCII files. We will 135 * consider incorporating EBCDIC support if there is enough demand. 136 * <p> 137 * <code> FTP.NON_PRINT_TEXT_FORMAT </code>, 138 * <code> FTP.STREAM_TRANSFER_MODE </code>, and 139 * <code> FTP.FILE_STRUCTURE </code> are the only supported formats, 140 * transfer modes, and file structures. 141 * <p> 142 * Because the handling of sockets on different platforms can differ 143 * significantly, the FTPClient automatically issues a new PORT (or EPRT) command 144 * prior to every transfer requiring that the server connect to the client's 145 * data port. This ensures identical problem-free behavior on Windows, Unix, 146 * and Macintosh platforms. Additionally, it relieves programmers from 147 * having to issue the PORT (or EPRT) command themselves and dealing with platform 148 * dependent issues. 149 * <p> 150 * Additionally, for security purposes, all data connections to the 151 * client are verified to ensure that they originated from the intended 152 * party (host and port). If a data connection is initiated by an unexpected 153 * party, the command will close the socket and throw an IOException. You 154 * may disable this behavior with 155 * {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()}. 156 * <p> 157 * You should keep in mind that the FTP server may choose to prematurely 158 * close a connection if the client has been idle for longer than a 159 * given time period (usually 900 seconds). The FTPClient class will detect a 160 * premature FTP server connection closing when it receives a 161 * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } 162 * response to a command. 163 * When that occurs, the FTP class method encountering that reply will throw 164 * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} 165 * . 166 * <code>FTPConnectionClosedException</code> 167 * is a subclass of <code> IOException </code> and therefore need not be 168 * caught separately, but if you are going to catch it separately, its 169 * catch block must appear before the more general <code> IOException </code> 170 * catch block. When you encounter an 171 * {@link org.apache.commons.net.ftp.FTPConnectionClosedException} 172 * , you must disconnect the connection with 173 * {@link #disconnect disconnect() } to properly clean up the 174 * system resources used by FTPClient. Before disconnecting, you may check the 175 * last reply code and text with 176 * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode }, 177 * {@link org.apache.commons.net.ftp.FTP#getReplyString getReplyString }, 178 * and 179 * {@link org.apache.commons.net.ftp.FTP#getReplyStrings getReplyStrings}. 180 * You may avoid server disconnections while the client is idle by 181 * periodically sending NOOP commands to the server. 182 * <p> 183 * Rather than list it separately for each method, we mention here that 184 * every method communicating with the server and throwing an IOException 185 * can also throw a 186 * {@link org.apache.commons.net.MalformedServerReplyException} 187 * , which is a subclass 188 * of IOException. A MalformedServerReplyException will be thrown when 189 * the reply received from the server deviates enough from the protocol 190 * specification that it cannot be interpreted in a useful manner despite 191 * attempts to be as lenient as possible. 192 * <p> 193 * Listing API Examples 194 * Both paged and unpaged examples of directory listings are available, 195 * as follows: 196 * <p> 197 * Unpaged (whole list) access, using a parser accessible by auto-detect: 198 * <pre> 199 * FTPClient f = new FTPClient(); 200 * f.connect(server); 201 * f.login(username, password); 202 * FTPFile[] files = f.listFiles(directory); 203 * </pre> 204 * <p> 205 * Paged access, using a parser not accessible by auto-detect. The class 206 * defined in the first parameter of initateListParsing should be derived 207 * from org.apache.commons.net.FTPFileEntryParser: 208 * <pre> 209 * FTPClient f = new FTPClient(); 210 * f.connect(server); 211 * f.login(username, password); 212 * FTPListParseEngine engine = 213 * f.initiateListParsing("com.whatever.YourOwnParser", directory); 214 * 215 * while (engine.hasNext()) { 216 * FTPFile[] files = engine.getNext(25); // "page size" you want 217 * //do whatever you want with these files, display them, etc. 218 * //expensive FTPFile objects not created until needed. 219 * } 220 * </pre> 221 * <p> 222 * Paged access, using a parser accessible by auto-detect: 223 * <pre> 224 * FTPClient f = new FTPClient(); 225 * f.connect(server); 226 * f.login(username, password); 227 * FTPListParseEngine engine = f.initiateListParsing(directory); 228 * 229 * while (engine.hasNext()) { 230 * FTPFile[] files = engine.getNext(25); // "page size" you want 231 * //do whatever you want with these files, display them, etc. 232 * //expensive FTPFile objects not created until needed. 233 * } 234 * </pre> 235 * <p> 236 * For examples of using FTPClient on servers whose directory listings 237 * <ul> 238 * <li>use languages other than English</li> 239 * <li>use date formats other than the American English "standard" <code>MM d yyyy</code></li> 240 * <li>are in different timezones and you need accurate timestamps for dependency checking 241 * as in Ant</li> 242 * </ul>see {@link FTPClientConfig FTPClientConfig}. 243 * <p> 244 * <b>Control channel keep-alive feature</b>: 245 * <p> 246 * <b>Please note:</b> this does not apply to the methods where the user is responsible for writing or reading 247 * the data stream, i.e. {@link #retrieveFileStream(String)} , {@link #storeFileStream(String)} 248 * and the other xxxFileStream methods 249 * <p> 250 * During file transfers, the data connection is busy, but the control connection is idle. 251 * FTP servers know that the control connection is in use, so won't close it through lack of activity, 252 * but it's a lot harder for network routers to know that the control and data connections are associated 253 * with each other. 254 * Some routers may treat the control connection as idle, and disconnect it if the transfer over the data 255 * connection takes longer than the allowable idle time for the router. 256 * <br> 257 * One solution to this is to send a safe command (i.e. NOOP) over the control connection to reset the router's 258 * idle timer. This is enabled as follows: 259 * <pre> 260 * ftpClient.setControlKeepAliveTimeout(300); // set timeout to 5 minutes 261 * </pre> 262 * This will cause the file upload/download methods to send a NOOP approximately every 5 minutes. 263 * The following public methods support this: 264 * <ul> 265 * <li>{@link #retrieveFile(String, OutputStream)}</li> 266 * <li>{@link #appendFile(String, InputStream)}</li> 267 * <li>{@link #storeFile(String, InputStream)}</li> 268 * <li>{@link #storeUniqueFile(InputStream)}</li> 269 * <li>{@link #storeUniqueFileStream(String)}</li> 270 * </ul> 271 * This feature does not apply to the methods where the user is responsible for writing or reading 272 * the data stream, i.e. {@link #retrieveFileStream(String)} , {@link #storeFileStream(String)} 273 * and the other xxxFileStream methods. 274 * In such cases, the user is responsible for keeping the control connection alive if necessary. 275 * <p> 276 * The implementation currently uses a {@link CopyStreamListener} which is passed to the 277 * {@link Util#copyStream(InputStream, OutputStream, int, long, CopyStreamListener, boolean)} 278 * method, so the timing is partially dependent on how long each block transfer takes. 279 * <p> 280 * <b>This keep-alive feature is optional; if it does not help or causes problems then don't use it.</b> 281 * 282 * @see #FTP_SYSTEM_TYPE 283 * @see #SYSTEM_TYPE_PROPERTIES 284 * @see FTP 285 * @see FTPConnectionClosedException 286 * @see FTPFileEntryParser 287 * @see FTPFileEntryParserFactory 288 * @see DefaultFTPFileEntryParserFactory 289 * @see FTPClientConfig 290 * 291 * @see org.apache.commons.net.MalformedServerReplyException 292 */ 293public class FTPClient extends FTP 294implements Configurable 295{ 296 /** 297 * The system property ({@value}) which can be used to override the system type.<br> 298 * If defined, the value will be used to create any automatically created parsers. 299 * 300 * @since 3.0 301 */ 302 public static final String FTP_SYSTEM_TYPE = "org.apache.commons.net.ftp.systemType"; 303 304 /** 305 * The system property ({@value}) which can be used as the default system type.<br> 306 * If defined, the value will be used if the SYST command fails. 307 * 308 * @since 3.1 309 */ 310 public static final String FTP_SYSTEM_TYPE_DEFAULT = "org.apache.commons.net.ftp.systemType.default"; 311 312 /** 313 * The name of an optional systemType properties file ({@value}), which is loaded 314 * using {@link Class#getResourceAsStream(String)}.<br> 315 * The entries are the systemType (as determined by {@link FTPClient#getSystemType}) 316 * and the values are the replacement type or parserClass, which is passed to 317 * {@link FTPFileEntryParserFactory#createFileEntryParser(String)}.<br> 318 * For example: 319 * <pre> 320 * Plan 9=Unix 321 * OS410=org.apache.commons.net.ftp.parser.OS400FTPEntryParser 322 * </pre> 323 * 324 * @since 3.0 325 */ 326 public static final String SYSTEM_TYPE_PROPERTIES = "/systemType.properties"; 327 328 /** 329 * A constant indicating the FTP session is expecting all transfers 330 * to occur between the client (local) and server and that the server 331 * should connect to the client's data port to initiate a data transfer. 332 * This is the default data connection mode when and FTPClient instance 333 * is created. 334 */ 335 public static final int ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0; 336 /** 337 * A constant indicating the FTP session is expecting all transfers 338 * to occur between two remote servers and that the server 339 * the client is connected to should connect to the other server's 340 * data port to initiate a data transfer. 341 */ 342 public static final int ACTIVE_REMOTE_DATA_CONNECTION_MODE = 1; 343 /** 344 * A constant indicating the FTP session is expecting all transfers 345 * to occur between the client (local) and server and that the server 346 * is in passive mode, requiring the client to connect to the 347 * server's data port to initiate a transfer. 348 */ 349 public static final int PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2; 350 /** 351 * A constant indicating the FTP session is expecting all transfers 352 * to occur between two remote servers and that the server 353 * the client is connected to is in passive mode, requiring the other 354 * server to connect to the first server's data port to initiate a data 355 * transfer. 356 */ 357 public static final int PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3; 358 359 private int dataConnectionMode; 360 private int dataTimeout; 361 private int passivePort; 362 private String passiveHost; 363 private final Random random; 364 private int activeMinPort; 365 private int activeMaxPort; 366 private InetAddress activeExternalHost; 367 private InetAddress reportActiveExternalHost; // overrides __activeExternalHost in EPRT/PORT commands 368 /** The address to bind to on passive connections, if necessary. */ 369 private InetAddress passiveLocalHost; 370 371 private int fileType; 372 @SuppressWarnings("unused") // fields are written, but currently not read 373 private int fileFormat; 374 @SuppressWarnings("unused") // field is written, but currently not read 375 private int fileStructure; 376 @SuppressWarnings("unused") // field is written, but currently not read 377 private int fileTransferMode; 378 private boolean remoteVerificationEnabled; 379 private long restartOffset; 380 private FTPFileEntryParserFactory parserFactory; 381 private int bufferSize; // buffersize for buffered data streams 382 private int sendDataSocketBufferSize; 383 private int receiveDataSocketBufferSize; 384 private boolean listHiddenFiles; 385 private boolean useEPSVwithIPv4; // whether to attempt EPSV with an IPv4 connection 386 387 // __systemName is a cached value that should not be referenced directly 388 // except when assigned in getSystemName and __initDefaults. 389 private String systemName; 390 391 // __entryParser is a cached value that should not be referenced directly 392 // except when assigned in listFiles(String, String) and __initDefaults. 393 private FTPFileEntryParser entryParser; 394 395 // Key used to create the parser; necessary to ensure that the parser type is not ignored 396 private String entryParserKey; 397 398 private FTPClientConfig configuration; 399 400 // Listener used by store/retrieve methods to handle keepalive 401 private CopyStreamListener copyStreamListener; 402 403 // How long to wait before sending another control keep-alive message 404 private long controlKeepAliveTimeout; 405 406 // How long to wait (ms) for keepalive message replies before continuing 407 // Most FTP servers don't seem to support concurrent control and data connection usage 408 private int controlKeepAliveReplyTimeout=1000; 409 410 // Debug counts for NOOP acks 411 private int[] cslDebug; 412 413 /** 414 * Enable or disable replacement of internal IP in passive mode. Default enabled 415 * using {code NatServerResolverImpl}. 416 */ 417 private HostnameResolver passiveNatWorkaroundStrategy = new NatServerResolverImpl(this); 418 419 /** Pattern for PASV mode responses. Groups: (n,n,n,n),(n),(n) */ 420 private static final java.util.regex.Pattern PARMS_PAT; 421 422 static { 423 PARMS_PAT = java.util.regex.Pattern.compile( 424 "(\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}),(\\d{1,3}),(\\d{1,3})"); 425 } 426 427 /** Controls the automatic server encoding detection (only UTF-8 supported). */ 428 private boolean autodetectEncoding = false; 429 430 /** Map of FEAT responses. If null, has not been initialised. */ 431 private HashMap<String, Set<String>> featuresMap; 432 433 private static class PropertiesSingleton { 434 435 static final Properties PROPERTIES; 436 437 static { 438 final InputStream resourceAsStream = FTPClient.class.getResourceAsStream(SYSTEM_TYPE_PROPERTIES); 439 Properties p = null; 440 if (resourceAsStream != null) { 441 p = new Properties(); 442 try { 443 p.load(resourceAsStream); 444 } catch (final IOException e) { 445 // Ignored 446 } finally { 447 try { 448 resourceAsStream.close(); 449 } catch (final IOException e) { 450 // Ignored 451 } 452 } 453 } 454 PROPERTIES = p; 455 } 456 457 } 458 private static Properties getOverrideProperties(){ 459 return PropertiesSingleton.PROPERTIES; 460 } 461 462 /** 463 * Default FTPClient constructor. Creates a new FTPClient instance 464 * with the data connection mode set to 465 * <code> ACTIVE_LOCAL_DATA_CONNECTION_MODE </code>, the file type 466 * set to <code> FTP.ASCII_FILE_TYPE </code>, the 467 * file format set to <code> FTP.NON_PRINT_TEXT_FORMAT </code>, 468 * the file structure set to <code> FTP.FILE_STRUCTURE </code>, and 469 * the transfer mode set to <code> FTP.STREAM_TRANSFER_MODE </code>. 470 * <p> 471 * The list parsing auto-detect feature can be configured to use lenient future 472 * dates (short dates may be up to one day in the future) as follows: 473 * <pre> 474 * FTPClient ftp = new FTPClient(); 475 * FTPClientConfig config = new FTPClientConfig(); 476 * config.setLenientFutureDates(true); 477 * ftp.configure(config ); 478 * </pre> 479 */ 480 public FTPClient() 481 { 482 initDefaults(); 483 dataTimeout = -1; 484 remoteVerificationEnabled = true; 485 parserFactory = new DefaultFTPFileEntryParserFactory(); 486 configuration = null; 487 listHiddenFiles = false; 488 useEPSVwithIPv4 = false; 489 random = new Random(); 490 passiveLocalHost = null; 491 } 492 493 494 private void initDefaults() 495 { 496 dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; 497 passiveHost = null; 498 passivePort = -1; 499 activeExternalHost = null; 500 reportActiveExternalHost = null; 501 activeMinPort = 0; 502 activeMaxPort = 0; 503 fileType = FTP.ASCII_FILE_TYPE; 504 fileStructure = FTP.FILE_STRUCTURE; 505 fileFormat = FTP.NON_PRINT_TEXT_FORMAT; 506 fileTransferMode = FTP.STREAM_TRANSFER_MODE; 507 restartOffset = 0; 508 systemName = null; 509 entryParser = null; 510 entryParserKey = ""; 511 featuresMap = null; 512 } 513 514 /** 515 * Parse the pathname from a CWD reply. 516 * <p> 517 * According to RFC959 (http://www.ietf.org/rfc/rfc959.txt), 518 * it should be the same as for MKD i.e. 519 * {@code 257<space>"<directory-name>"[<space>commentary]} 520 * where any double-quotes in {@code <directory-name>} are doubled. 521 * Unlike MKD, the commentary is optional. 522 * <p> 523 * However, see NET-442 for an exception. 524 * 525 * @param reply 526 * @return the pathname, without enclosing quotes, 527 * or the full string after the reply code and space if the syntax is invalid 528 * (i.e. enclosing quotes are missing or embedded quotes are not doubled) 529 */ 530 // package protected for access by test cases 531 static String parsePathname(final String reply) 532 { 533 final String param = reply.substring(REPLY_CODE_LEN + 1); 534 if (param.startsWith("\"")) { 535 final StringBuilder sb = new StringBuilder(); 536 boolean quoteSeen = false; 537 // start after initial quote 538 for(int i=1; i < param.length(); i++) { 539 final char ch = param.charAt(i); 540 if (ch=='"') { 541 if (quoteSeen) { 542 sb.append(ch); 543 quoteSeen=false; 544 } else { 545 // don't output yet, in case doubled 546 quoteSeen=true; 547 } 548 } else { 549 if (quoteSeen) { // found lone trailing quote within string 550 return sb.toString(); 551 } 552 sb.append(ch); // just another character 553 } 554 } 555 if (quoteSeen) { // found lone trailing quote at end of string 556 return sb.toString(); 557 } 558 } 559 // malformed reply, return all after reply code and space 560 return param; 561 } 562 563 /** 564 * @since 3.1 565 * @param reply the reply to parse 566 * @throws MalformedServerReplyException if the server reply does not match (n,n,n,n),(n),(n) 567 */ 568 protected void _parsePassiveModeReply(final String reply) 569 throws MalformedServerReplyException 570 { 571 final java.util.regex.Matcher m = PARMS_PAT.matcher(reply); 572 if (!m.find()) { 573 throw new MalformedServerReplyException( 574 "Could not parse passive host information.\nServer Reply: " + reply); 575 } 576 577 this.passiveHost = "0,0,0,0".equals(m.group(1)) ? _socket_.getInetAddress().getHostAddress() : 578 m.group(1).replace(',', '.'); // Fix up to look like IP address 579 580 try 581 { 582 final int oct1 = Integer.parseInt(m.group(2)); 583 final int oct2 = Integer.parseInt(m.group(3)); 584 passivePort = (oct1 << 8) | oct2; 585 } 586 catch (final NumberFormatException e) 587 { 588 throw new MalformedServerReplyException( 589 "Could not parse passive port information.\nServer Reply: " + reply); 590 } 591 592 if (passiveNatWorkaroundStrategy != null) { 593 try { 594 final String newPassiveHost = passiveNatWorkaroundStrategy.resolve(this.passiveHost); 595 if (!this.passiveHost.equals(newPassiveHost)) { 596 fireReplyReceived(0, 597 "[Replacing PASV mode reply address "+this.passiveHost+" with "+newPassiveHost+"]\n"); 598 this.passiveHost = newPassiveHost; 599 } 600 } catch (final UnknownHostException e) { // Should not happen as we are passing in an IP address 601 throw new MalformedServerReplyException( 602 "Could not parse passive host information.\nServer Reply: " + reply); 603 } 604 } 605 } 606 607 protected void _parseExtendedPassiveModeReply(String reply) 608 throws MalformedServerReplyException 609 { 610 reply = reply.substring(reply.indexOf('(') + 1, 611 reply.indexOf(')')).trim(); 612 613 char delim1, delim2, delim3, delim4; 614 delim1 = reply.charAt(0); 615 delim2 = reply.charAt(1); 616 delim3 = reply.charAt(2); 617 delim4 = reply.charAt(reply.length()-1); 618 619 if (!(delim1 == delim2) || !(delim2 == delim3) 620 || !(delim3 == delim4)) { 621 throw new MalformedServerReplyException( 622 "Could not parse extended passive host information.\nServer Reply: " + reply); 623 } 624 625 int port; 626 try 627 { 628 port = Integer.parseInt(reply.substring(3, reply.length()-1)); 629 } 630 catch (final NumberFormatException e) 631 { 632 throw new MalformedServerReplyException( 633 "Could not parse extended passive host information.\nServer Reply: " + reply); 634 } 635 636 637 // in EPSV mode, the passive host address is implicit 638 this.passiveHost = getRemoteAddress().getHostAddress(); 639 this.passivePort = port; 640 } 641 642 private boolean storeFile(final FTPCmd command, final String remote, final InputStream local) 643 throws IOException 644 { 645 return _storeFile(command.getCommand(), remote, local); 646 } 647 648 /** 649 * @since 3.1 650 * @param command the command to send 651 * @param remote the remote file name 652 * @param local The local InputStream from which to read the data to 653 * be written/appended to the remote file. 654 * @return true if successful 655 * @throws IOException on error 656 */ 657 protected boolean _storeFile(final String command, final String remote, final InputStream local) 658 throws IOException 659 { 660 final Socket socket = _openDataConnection_(command, remote); 661 662 if (socket == null) { 663 return false; 664 } 665 666 final OutputStream output; 667 668 if (fileType == ASCII_FILE_TYPE) { 669 output = new ToNetASCIIOutputStream(getBufferedOutputStream(socket.getOutputStream())); 670 } else { 671 output = getBufferedOutputStream(socket.getOutputStream()); 672 } 673 674 CSL csl = null; 675 if (controlKeepAliveTimeout > 0) { 676 csl = new CSL(this, controlKeepAliveTimeout, controlKeepAliveReplyTimeout); 677 } 678 679 // Treat everything else as binary for now 680 try 681 { 682 Util.copyStream(local, output, getBufferSize(), 683 CopyStreamEvent.UNKNOWN_STREAM_SIZE, mergeListeners(csl), 684 false); 685 output.close(); // ensure the file is fully written 686 socket.close(); // done writing the file 687 688 // Get the transfer response 689 return completePendingCommand(); 690 } 691 catch (final IOException e) 692 { 693 Util.closeQuietly(output); // ignore close errors here 694 Util.closeQuietly(socket); // ignore close errors here 695 throw e; 696 } finally { 697 if (csl != null) { 698 cslDebug = csl.cleanUp(); // fetch any outstanding keepalive replies 699 } 700 } 701 } 702 703 private OutputStream storeFileStream(final FTPCmd command, final String remote) 704 throws IOException 705 { 706 return _storeFileStream(command.getCommand(), remote); 707 } 708 709 /** 710 * @param command the command to send 711 * @param remote the remote file name 712 * @return the output stream to write to 713 * @throws IOException on error 714 * @since 3.1 715 */ 716 protected OutputStream _storeFileStream(final String command, final String remote) 717 throws IOException 718 { 719 final Socket socket = _openDataConnection_(command, remote); 720 721 if (socket == null) { 722 return null; 723 } 724 725 final OutputStream output; 726 if (fileType == ASCII_FILE_TYPE) { 727 // We buffer ascii transfers because the buffering has to 728 // be interposed between ToNetASCIIOutputSream and the underlying 729 // socket output stream. We don't buffer binary transfers 730 // because we don't want to impose a buffering policy on the 731 // programmer if possible. Programmers can decide on their 732 // own if they want to wrap the SocketOutputStream we return 733 // for file types other than ASCII. 734 output = new ToNetASCIIOutputStream(getBufferedOutputStream(socket.getOutputStream())); 735 } else { 736 output = socket.getOutputStream(); 737 } 738 return new org.apache.commons.net.io.SocketOutputStream(socket, output); 739 } 740 741 742 /** 743 * Establishes a data connection with the FTP server, returning 744 * a Socket for the connection if successful. If a restart 745 * offset has been set with {@link #setRestartOffset(long)}, 746 * a REST command is issued to the server with the offset as 747 * an argument before establishing the data connection. Active 748 * mode connections also cause a local PORT command to be issued. 749 * 750 * @param command The int representation of the FTP command to send. 751 * @param arg The arguments to the FTP command. If this parameter is 752 * set to null, then the command is sent with no argument. 753 * @return A Socket corresponding to the established data connection. 754 * Null is returned if an FTP protocol error is reported at 755 * any point during the establishment and initialization of 756 * the connection. 757 * @throws IOException If an I/O error occurs while either sending a 758 * command to the server or receiving a reply from the server. 759 * @deprecated (3.3) Use {@link #_openDataConnection_(FTPCmd, String)} instead 760 */ 761 @Deprecated 762 protected Socket _openDataConnection_(final int command, final String arg) 763 throws IOException 764 { 765 return _openDataConnection_(FTPCommand.getCommand(command), arg); 766 } 767 768 /** 769 * Establishes a data connection with the FTP server, returning 770 * a Socket for the connection if successful. If a restart 771 * offset has been set with {@link #setRestartOffset(long)}, 772 * a REST command is issued to the server with the offset as 773 * an argument before establishing the data connection. Active 774 * mode connections also cause a local PORT command to be issued. 775 * 776 * @param command The int representation of the FTP command to send. 777 * @param arg The arguments to the FTP command. If this parameter is 778 * set to null, then the command is sent with no argument. 779 * @return A Socket corresponding to the established data connection. 780 * Null is returned if an FTP protocol error is reported at 781 * any point during the establishment and initialization of 782 * the connection. 783 * @throws IOException If an I/O error occurs while either sending a 784 * command to the server or receiving a reply from the server. 785 * @since 3.3 786 */ 787 protected Socket _openDataConnection_(final FTPCmd command, final String arg) 788 throws IOException 789 { 790 return _openDataConnection_(command.getCommand(), arg); 791 } 792 793 /** 794 * Establishes a data connection with the FTP server, returning 795 * a Socket for the connection if successful. If a restart 796 * offset has been set with {@link #setRestartOffset(long)}, 797 * a REST command is issued to the server with the offset as 798 * an argument before establishing the data connection. Active 799 * mode connections also cause a local PORT command to be issued. 800 * 801 * @param command The text representation of the FTP command to send. 802 * @param arg The arguments to the FTP command. If this parameter is 803 * set to null, then the command is sent with no argument. 804 * @return A Socket corresponding to the established data connection. 805 * Null is returned if an FTP protocol error is reported at 806 * any point during the establishment and initialization of 807 * the connection. 808 * @throws IOException If an I/O error occurs while either sending a 809 * command to the server or receiving a reply from the server. 810 * @since 3.1 811 */ 812 protected Socket _openDataConnection_(final String command, final String arg) 813 throws IOException 814 { 815 if (dataConnectionMode != ACTIVE_LOCAL_DATA_CONNECTION_MODE && 816 dataConnectionMode != PASSIVE_LOCAL_DATA_CONNECTION_MODE) { 817 return null; 818 } 819 820 final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address; 821 822 Socket socket; 823 824 if (dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE) 825 { 826 // if no activePortRange was set (correctly) -> getActivePort() = 0 827 // -> new ServerSocket(0) -> bind to any free local port 828 try (final ServerSocket server = _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress())) { 829 // Try EPRT only if remote server is over IPv6, if not use PORT, 830 // because EPRT has no advantage over PORT on IPv4. 831 // It could even have the disadvantage, 832 // that EPRT will make the data connection fail, because 833 // today's intelligent NAT Firewalls are able to 834 // substitute IP addresses in the PORT command, 835 // but might not be able to recognize the EPRT command. 836 if (isInet6Address) { 837 if (!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(), server.getLocalPort()))) { 838 return null; 839 } 840 } else { 841 if (!FTPReply.isPositiveCompletion(port(getReportHostAddress(), server.getLocalPort()))) { 842 return null; 843 } 844 } 845 846 if ((restartOffset > 0) && !restart(restartOffset)) { 847 return null; 848 } 849 850 if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) { 851 return null; 852 } 853 854 // For now, let's just use the data timeout value for waiting for 855 // the data connection. It may be desirable to let this be a 856 // separately configurable value. In any case, we really want 857 // to allow preventing the accept from blocking indefinitely. 858 if (dataTimeout >= 0) { 859 server.setSoTimeout(dataTimeout); 860 } 861 socket = server.accept(); 862 863 // Ensure the timeout is set before any commands are issued on the new socket 864 if (dataTimeout >= 0) { 865 socket.setSoTimeout(dataTimeout); 866 } 867 if (receiveDataSocketBufferSize > 0) { 868 socket.setReceiveBufferSize(receiveDataSocketBufferSize); 869 } 870 if (sendDataSocketBufferSize > 0) { 871 socket.setSendBufferSize(sendDataSocketBufferSize); 872 } 873 } 874 } 875 else 876 { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE 877 878 // Try EPSV command first on IPv6 - and IPv4 if enabled. 879 // When using IPv4 with NAT it has the advantage 880 // to work with more rare configurations. 881 // E.g. if FTP server has a static PASV address (external network) 882 // and the client is coming from another internal network. 883 // In that case the data connection after PASV command would fail, 884 // while EPSV would make the client succeed by taking just the port. 885 final boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address; 886 if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) 887 { 888 _parseExtendedPassiveModeReply(_replyLines.get(0)); 889 } 890 else 891 { 892 if (isInet6Address) { 893 return null; // Must use EPSV for IPV6 894 } 895 // If EPSV failed on IPV4, revert to PASV 896 if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) { 897 return null; 898 } 899 _parsePassiveModeReply(_replyLines.get(0)); 900 } 901 902 socket = _socketFactory_.createSocket(); 903 if (receiveDataSocketBufferSize > 0) { 904 socket.setReceiveBufferSize(receiveDataSocketBufferSize); 905 } 906 if (sendDataSocketBufferSize > 0) { 907 socket.setSendBufferSize(sendDataSocketBufferSize); 908 } 909 if (passiveLocalHost != null) { 910 socket.bind(new InetSocketAddress(passiveLocalHost, 0)); 911 } 912 913 // For now, let's just use the data timeout value for waiting for 914 // the data connection. It may be desirable to let this be a 915 // separately configurable value. In any case, we really want 916 // to allow preventing the accept from blocking indefinitely. 917 if (dataTimeout >= 0) { 918 socket.setSoTimeout(dataTimeout); 919 } 920 921 socket.connect(new InetSocketAddress(passiveHost, passivePort), connectTimeout); 922 if ((restartOffset > 0) && !restart(restartOffset)) 923 { 924 socket.close(); 925 return null; 926 } 927 928 if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) 929 { 930 socket.close(); 931 return null; 932 } 933 } 934 935 if (remoteVerificationEnabled && !verifyRemote(socket)) 936 { 937 // Grab the host before we close the socket to avoid NET-663 938 final InetAddress socketHost = socket.getInetAddress(); 939 940 socket.close(); 941 942 throw new IOException( 943 "Host attempting data connection " + socketHost.getHostAddress() + 944 " is not same as server " + getRemoteAddress().getHostAddress()); 945 } 946 947 return socket; 948 } 949 950 951 @Override 952 protected void _connectAction_() throws IOException 953 { 954 _connectAction_(null); 955 } 956 957 958 /** 959 * @param socketIsReader the reader to reuse (if non-null) 960 * @throws IOException on error 961 * @since 3.4 962 */ 963 @Override 964 protected void _connectAction_(final Reader socketIsReader) throws IOException 965 { 966 super._connectAction_(socketIsReader); // sets up _input_ and _output_ 967 initDefaults(); 968 // must be after super._connectAction_(), because otherwise we get an 969 // Exception claiming we're not connected 970 if ( autodetectEncoding ) 971 { 972 final ArrayList<String> oldReplyLines = new ArrayList<> (_replyLines); 973 final int oldReplyCode = _replyCode; 974 if ( hasFeature("UTF8") || hasFeature("UTF-8")) // UTF8 appears to be the default 975 { 976 setControlEncoding("UTF-8"); 977 _controlInput_ = 978 new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding())); 979 _controlOutput_ = 980 new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding())); 981 } 982 // restore the original reply (server greeting) 983 _replyLines.clear(); 984 _replyLines.addAll(oldReplyLines); 985 _replyCode = oldReplyCode; 986 _newReplyString = true; 987 } 988 } 989 990 991 /** 992 * Sets the timeout in milliseconds to use when reading from the 993 * data connection. This timeout will be set immediately after 994 * opening the data connection, provided that the value is ≥ 0. 995 * <p> 996 * <b>Note:</b> the timeout will also be applied when calling accept() 997 * whilst establishing an active local data connection. 998 * @param timeout The default timeout in milliseconds that is used when 999 * opening a data connection socket. The value 0 means an infinite timeout. 1000 */ 1001 public void setDataTimeout(final int timeout) 1002 { 1003 dataTimeout = timeout; 1004 } 1005 1006 /** 1007 * set the factory used for parser creation to the supplied factory object. 1008 * 1009 * @param parserFactory 1010 * factory object used to create FTPFileEntryParsers 1011 * 1012 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory 1013 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory 1014 */ 1015 public void setParserFactory(final FTPFileEntryParserFactory parserFactory) { 1016 this.parserFactory = parserFactory; 1017 } 1018 1019 1020 /** 1021 * Closes the connection to the FTP server and restores 1022 * connection parameters to the default values. 1023 * 1024 * @throws IOException If an error occurs while disconnecting. 1025 */ 1026 @Override 1027 public void disconnect() throws IOException 1028 { 1029 super.disconnect(); 1030 initDefaults(); 1031 } 1032 1033 1034 /** 1035 * Enable or disable verification that the remote host taking part 1036 * of a data connection is the same as the host to which the control 1037 * connection is attached. The default is for verification to be 1038 * enabled. You may set this value at any time, whether the 1039 * FTPClient is currently connected or not. 1040 * 1041 * @param enable True to enable verification, false to disable verification. 1042 */ 1043 public void setRemoteVerificationEnabled(final boolean enable) 1044 { 1045 remoteVerificationEnabled = enable; 1046 } 1047 1048 /** 1049 * Return whether or not verification of the remote host participating 1050 * in data connections is enabled. The default behavior is for 1051 * verification to be enabled. 1052 * 1053 * @return True if verification is enabled, false if not. 1054 */ 1055 public boolean isRemoteVerificationEnabled() 1056 { 1057 return remoteVerificationEnabled; 1058 } 1059 1060 /** 1061 * Login to the FTP server using the provided username and password. 1062 * 1063 * @param username The username to login under. 1064 * @param password The password to use. 1065 * @return True if successfully completed, false if not. 1066 * @throws FTPConnectionClosedException 1067 * If the FTP server prematurely closes the connection as a result 1068 * of the client being idle or some other reason causing the server 1069 * to send FTP reply code 421. This exception may be caught either 1070 * as an IOException or independently as itself. 1071 * @throws IOException If an I/O error occurs while either sending a 1072 * command to the server or receiving a reply from the server. 1073 */ 1074 public boolean login(final String username, final String password) throws IOException 1075 { 1076 1077 user(username); 1078 1079 if (FTPReply.isPositiveCompletion(_replyCode)) { 1080 return true; 1081 } 1082 1083 // If we get here, we either have an error code, or an intermmediate 1084 // reply requesting password. 1085 if (!FTPReply.isPositiveIntermediate(_replyCode)) { 1086 return false; 1087 } 1088 1089 return FTPReply.isPositiveCompletion(pass(password)); 1090 } 1091 1092 1093 /** 1094 * Login to the FTP server using the provided username, password, 1095 * and account. If no account is required by the server, only 1096 * the username and password, the account information is not used. 1097 * 1098 * @param username The username to login under. 1099 * @param password The password to use. 1100 * @param account The account to use. 1101 * @return True if successfully completed, false if not. 1102 * @throws FTPConnectionClosedException 1103 * If the FTP server prematurely closes the connection as a result 1104 * of the client being idle or some other reason causing the server 1105 * to send FTP reply code 421. This exception may be caught either 1106 * as an IOException or independently as itself. 1107 * @throws IOException If an I/O error occurs while either sending a 1108 * command to the server or receiving a reply from the server. 1109 */ 1110 public boolean login(final String username, final String password, final String account) 1111 throws IOException 1112 { 1113 user(username); 1114 1115 if (FTPReply.isPositiveCompletion(_replyCode)) { 1116 return true; 1117 } 1118 1119 // If we get here, we either have an error code, or an intermmediate 1120 // reply requesting password. 1121 if (!FTPReply.isPositiveIntermediate(_replyCode)) { 1122 return false; 1123 } 1124 1125 pass(password); 1126 1127 if (FTPReply.isPositiveCompletion(_replyCode)) { 1128 return true; 1129 } 1130 1131 if (!FTPReply.isPositiveIntermediate(_replyCode)) { 1132 return false; 1133 } 1134 1135 return FTPReply.isPositiveCompletion(acct(account)); 1136 } 1137 1138 /** 1139 * Logout of the FTP server by sending the QUIT command. 1140 * 1141 * @return True if successfully completed, false if not. 1142 * @throws FTPConnectionClosedException 1143 * If the FTP server prematurely closes the connection as a result 1144 * of the client being idle or some other reason causing the server 1145 * to send FTP reply code 421. This exception may be caught either 1146 * as an IOException or independently as itself. 1147 * @throws IOException If an I/O error occurs while either sending a 1148 * command to the server or receiving a reply from the server. 1149 */ 1150 public boolean logout() throws IOException 1151 { 1152 return FTPReply.isPositiveCompletion(quit()); 1153 } 1154 1155 1156 /** 1157 * Change the current working directory of the FTP session. 1158 * 1159 * @param pathname The new current working directory. 1160 * @return True if successfully completed, false if not. 1161 * @throws FTPConnectionClosedException 1162 * If the FTP server prematurely closes the connection as a result 1163 * of the client being idle or some other reason causing the server 1164 * to send FTP reply code 421. This exception may be caught either 1165 * as an IOException or independently as itself. 1166 * @throws IOException If an I/O error occurs while either sending a 1167 * command to the server or receiving a reply from the server. 1168 */ 1169 public boolean changeWorkingDirectory(final String pathname) throws IOException 1170 { 1171 return FTPReply.isPositiveCompletion(cwd(pathname)); 1172 } 1173 1174 1175 /** 1176 * Change to the parent directory of the current working directory. 1177 * 1178 * @return True if successfully completed, false if not. 1179 * @throws FTPConnectionClosedException 1180 * If the FTP server prematurely closes the connection as a result 1181 * of the client being idle or some other reason causing the server 1182 * to send FTP reply code 421. This exception may be caught either 1183 * as an IOException or independently as itself. 1184 * @throws IOException If an I/O error occurs while either sending a 1185 * command to the server or receiving a reply from the server. 1186 */ 1187 public boolean changeToParentDirectory() throws IOException 1188 { 1189 return FTPReply.isPositiveCompletion(cdup()); 1190 } 1191 1192 1193 /** 1194 * Issue the FTP SMNT command. 1195 * 1196 * @param pathname The pathname to mount. 1197 * @return True if successfully completed, false if not. 1198 * @throws FTPConnectionClosedException 1199 * If the FTP server prematurely closes the connection as a result 1200 * of the client being idle or some other reason causing the server 1201 * to send FTP reply code 421. This exception may be caught either 1202 * as an IOException or independently as itself. 1203 * @throws IOException If an I/O error occurs while either sending a 1204 * command to the server or receiving a reply from the server. 1205 */ 1206 public boolean structureMount(final String pathname) throws IOException 1207 { 1208 return FTPReply.isPositiveCompletion(smnt(pathname)); 1209 } 1210 1211 /** 1212 * Reinitialize the FTP session. Not all FTP servers support this 1213 * command, which issues the FTP REIN command. 1214 * 1215 * @return True if successfully completed, false if not. 1216 * @throws FTPConnectionClosedException 1217 * If the FTP server prematurely closes the connection as a result 1218 * of the client being idle or some other reason causing the server 1219 * to send FTP reply code 421. This exception may be caught either 1220 * as an IOException or independently as itself. 1221 * @throws IOException If an I/O error occurs while either sending a 1222 * command to the server or receiving a reply from the server. 1223 * @since 3.4 (made public) 1224 */ 1225 public boolean reinitialize() throws IOException 1226 { 1227 rein(); 1228 1229 if (FTPReply.isPositiveCompletion(_replyCode) || 1230 (FTPReply.isPositivePreliminary(_replyCode) && 1231 FTPReply.isPositiveCompletion(getReply()))) 1232 { 1233 1234 initDefaults(); 1235 1236 return true; 1237 } 1238 1239 return false; 1240 } 1241 1242 1243 /** 1244 * Set the current data connection mode to 1245 * <code>ACTIVE_LOCAL_DATA_CONNECTION_MODE</code>. No communication 1246 * with the FTP server is conducted, but this causes all future data 1247 * transfers to require the FTP server to connect to the client's 1248 * data port. Additionally, to accommodate differences between socket 1249 * implementations on different platforms, this method causes the 1250 * client to issue a PORT command before every data transfer. 1251 */ 1252 public void enterLocalActiveMode() 1253 { 1254 dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; 1255 passiveHost = null; 1256 passivePort = -1; 1257 } 1258 1259 1260 /** 1261 * Set the current data connection mode to 1262 * <code> PASSIVE_LOCAL_DATA_CONNECTION_MODE </code>. Use this 1263 * method only for data transfers between the client and server. 1264 * This method causes a PASV (or EPSV) command to be issued to the server 1265 * before the opening of every data connection, telling the server to 1266 * open a data port to which the client will connect to conduct 1267 * data transfers. The FTPClient will stay in 1268 * <code> PASSIVE_LOCAL_DATA_CONNECTION_MODE </code> until the 1269 * mode is changed by calling some other method such as 1270 * {@link #enterLocalActiveMode enterLocalActiveMode() } 1271 * <p> 1272 * <b>N.B.</b> currently calling any connect method will reset the mode to 1273 * ACTIVE_LOCAL_DATA_CONNECTION_MODE. 1274 */ 1275 public void enterLocalPassiveMode() 1276 { 1277 dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE; 1278 // These will be set when just before a data connection is opened 1279 // in _openDataConnection_() 1280 passiveHost = null; 1281 passivePort = -1; 1282 } 1283 1284 1285 /** 1286 * Set the current data connection mode to 1287 * <code> ACTIVE_REMOTE_DATA_CONNECTION </code>. Use this method only 1288 * for server to server data transfers. This method issues a PORT 1289 * command to the server, indicating the other server and port to which 1290 * it should connect for data transfers. You must call this method 1291 * before EVERY server to server transfer attempt. The FTPClient will 1292 * NOT automatically continue to issue PORT commands. You also 1293 * must remember to call 1294 * {@link #enterLocalActiveMode enterLocalActiveMode() } if you 1295 * wish to return to the normal data connection mode. 1296 * 1297 * @param host The passive mode server accepting connections for data 1298 * transfers. 1299 * @param port The passive mode server's data port. 1300 * @return True if successfully completed, false if not. 1301 * @throws FTPConnectionClosedException 1302 * If the FTP server prematurely closes the connection as a result 1303 * of the client being idle or some other reason causing the server 1304 * to send FTP reply code 421. This exception may be caught either 1305 * as an IOException or independently as itself. 1306 * @throws IOException If an I/O error occurs while either sending a 1307 * command to the server or receiving a reply from the server. 1308 */ 1309 public boolean enterRemoteActiveMode(final InetAddress host, final int port) 1310 throws IOException 1311 { 1312 if (FTPReply.isPositiveCompletion(port(host, port))) 1313 { 1314 dataConnectionMode = ACTIVE_REMOTE_DATA_CONNECTION_MODE; 1315 passiveHost = null; 1316 passivePort = -1; 1317 return true; 1318 } 1319 return false; 1320 } 1321 1322 /** 1323 * Set the current data connection mode to 1324 * <code> PASSIVE_REMOTE_DATA_CONNECTION_MODE </code>. Use this 1325 * method only for server to server data transfers. 1326 * This method issues a PASV command to the server, telling it to 1327 * open a data port to which the active server will connect to conduct 1328 * data transfers. You must call this method 1329 * before EVERY server to server transfer attempt. The FTPClient will 1330 * NOT automatically continue to issue PASV commands. You also 1331 * must remember to call 1332 * {@link #enterLocalActiveMode enterLocalActiveMode() } if you 1333 * wish to return to the normal data connection mode. 1334 * 1335 * @return True if successfully completed, false if not. 1336 * @throws FTPConnectionClosedException 1337 * If the FTP server prematurely closes the connection as a result 1338 * of the client being idle or some other reason causing the server 1339 * to send FTP reply code 421. This exception may be caught either 1340 * as an IOException or independently as itself. 1341 * @throws IOException If an I/O error occurs while either sending a 1342 * command to the server or receiving a reply from the server. 1343 */ 1344 public boolean enterRemotePassiveMode() throws IOException 1345 { 1346 if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) { 1347 return false; 1348 } 1349 1350 dataConnectionMode = PASSIVE_REMOTE_DATA_CONNECTION_MODE; 1351 _parsePassiveModeReply(_replyLines.get(0)); 1352 1353 return true; 1354 } 1355 1356 /** 1357 * Returns the hostname or IP address (in the form of a string) returned 1358 * by the server when entering passive mode. If not in passive mode, 1359 * returns null. This method only returns a valid value AFTER a 1360 * data connection has been opened after a call to 1361 * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. 1362 * This is because FTPClient sends a PASV command to the server only 1363 * just before opening a data connection, and not when you call 1364 * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. 1365 * 1366 * @return The passive host name if in passive mode, otherwise null. 1367 */ 1368 public String getPassiveHost() 1369 { 1370 return passiveHost; 1371 } 1372 1373 /** 1374 * If in passive mode, returns the data port of the passive host. 1375 * This method only returns a valid value AFTER a 1376 * data connection has been opened after a call to 1377 * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. 1378 * This is because FTPClient sends a PASV command to the server only 1379 * just before opening a data connection, and not when you call 1380 * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. 1381 * 1382 * @return The data port of the passive server. If not in passive 1383 * mode, undefined. 1384 */ 1385 public int getPassivePort() 1386 { 1387 return passivePort; 1388 } 1389 1390 1391 /** 1392 * Returns the current data connection mode (one of the 1393 * <code> _DATA_CONNECTION_MODE </code> constants. 1394 * 1395 * @return The current data connection mode (one of the 1396 * <code> _DATA_CONNECTION_MODE </code> constants. 1397 */ 1398 public int getDataConnectionMode() 1399 { 1400 return dataConnectionMode; 1401 } 1402 1403 /** 1404 * Get the client port for active mode. 1405 * 1406 * @return The client port for active mode. 1407 */ 1408 private int getActivePort() 1409 { 1410 if (activeMinPort > 0 && activeMaxPort >= activeMinPort) 1411 { 1412 if (activeMaxPort == activeMinPort) { 1413 return activeMaxPort; 1414 } 1415 // Get a random port between the min and max port range 1416 return random.nextInt(activeMaxPort - activeMinPort + 1) + activeMinPort; 1417 } 1418 // default port 1419 return 0; 1420 } 1421 1422 /** 1423 * Get the host address for active mode; allows the local address to be overridden. 1424 * 1425 * @return __activeExternalHost if non-null, else getLocalAddress() 1426 * @see #setActiveExternalIPAddress(String) 1427 */ 1428 private InetAddress getHostAddress() 1429 { 1430 if (activeExternalHost != null) 1431 { 1432 return activeExternalHost; 1433 } 1434 // default local address 1435 return getLocalAddress(); 1436 } 1437 1438 /** 1439 * Get the reported host address for active mode EPRT/PORT commands; 1440 * allows override of {@link #getHostAddress()}. 1441 * 1442 * Useful for FTP Client behind Firewall NAT. 1443 * 1444 * @return __reportActiveExternalHost if non-null, else getHostAddress(); 1445 */ 1446 private InetAddress getReportHostAddress() { 1447 if (reportActiveExternalHost != null) { 1448 return reportActiveExternalHost ; 1449 } 1450 return getHostAddress(); 1451 } 1452 1453 /** 1454 * Set the client side port range in active mode. 1455 * 1456 * @param minPort The lowest available port (inclusive). 1457 * @param maxPort The highest available port (inclusive). 1458 * @since 2.2 1459 */ 1460 public void setActivePortRange(final int minPort, final int maxPort) 1461 { 1462 this.activeMinPort = minPort; 1463 this.activeMaxPort = maxPort; 1464 } 1465 1466 /** 1467 * Set the external IP address in active mode. 1468 * Useful when there are multiple network cards. 1469 * 1470 * @param ipAddress The external IP address of this machine. 1471 * @throws UnknownHostException if the ipAddress cannot be resolved 1472 * @since 2.2 1473 */ 1474 public void setActiveExternalIPAddress(final String ipAddress) throws UnknownHostException 1475 { 1476 this.activeExternalHost = InetAddress.getByName(ipAddress); 1477 } 1478 1479 /** 1480 * Set the local IP address to use in passive mode. 1481 * Useful when there are multiple network cards. 1482 * 1483 * @param ipAddress The local IP address of this machine. 1484 * @throws UnknownHostException if the ipAddress cannot be resolved 1485 */ 1486 public void setPassiveLocalIPAddress(final String ipAddress) throws UnknownHostException 1487 { 1488 this.passiveLocalHost = InetAddress.getByName(ipAddress); 1489 } 1490 1491 /** 1492 * Set the local IP address to use in passive mode. 1493 * Useful when there are multiple network cards. 1494 * 1495 * @param inetAddress The local IP address of this machine. 1496 */ 1497 public void setPassiveLocalIPAddress(final InetAddress inetAddress) 1498 { 1499 this.passiveLocalHost = inetAddress; 1500 } 1501 1502 /** 1503 * Set the local IP address in passive mode. 1504 * Useful when there are multiple network cards. 1505 * 1506 * @return The local IP address in passive mode. 1507 */ 1508 public InetAddress getPassiveLocalIPAddress() 1509 { 1510 return this.passiveLocalHost; 1511 } 1512 1513 /** 1514 * Set the external IP address to report in EPRT/PORT commands in active mode. 1515 * Useful when there are multiple network cards. 1516 * 1517 * @param ipAddress The external IP address of this machine. 1518 * @throws UnknownHostException if the ipAddress cannot be resolved 1519 * @since 3.1 1520 * @see #getReportHostAddress() 1521 */ 1522 public void setReportActiveExternalIPAddress(final String ipAddress) throws UnknownHostException 1523 { 1524 this.reportActiveExternalHost = InetAddress.getByName(ipAddress); 1525 } 1526 1527 1528 /** 1529 * Sets the file type to be transferred. This should be one of 1530 * <code> FTP.ASCII_FILE_TYPE </code>, <code> FTP.BINARY_FILE_TYPE</code>, 1531 * etc. The file type only needs to be set when you want to change the 1532 * type. After changing it, the new type stays in effect until you change 1533 * it again. The default file type is <code> FTP.ASCII_FILE_TYPE </code> 1534 * if this method is never called. 1535 * <br> 1536 * The server default is supposed to be ASCII (see RFC 959), however many 1537 * ftp servers default to BINARY. <b>To ensure correct operation with all servers, 1538 * always specify the appropriate file type after connecting to the server.</b> 1539 * <br> 1540 * <p> 1541 * <b>N.B.</b> currently calling any connect method will reset the type to 1542 * FTP.ASCII_FILE_TYPE. 1543 * @param fileType The <code> _FILE_TYPE </code> constant indicating the 1544 * type of file. 1545 * @return True if successfully completed, false if not. 1546 * @throws FTPConnectionClosedException 1547 * If the FTP server prematurely closes the connection as a result 1548 * of the client being idle or some other reason causing the server 1549 * to send FTP reply code 421. This exception may be caught either 1550 * as an IOException or independently as itself. 1551 * @throws IOException If an I/O error occurs while either sending a 1552 * command to the server or receiving a reply from the server. 1553 */ 1554 public boolean setFileType(final int fileType) throws IOException 1555 { 1556 if (FTPReply.isPositiveCompletion(type(fileType))) 1557 { 1558 this.fileType = fileType; 1559 this.fileFormat = FTP.NON_PRINT_TEXT_FORMAT; 1560 return true; 1561 } 1562 return false; 1563 } 1564 1565 1566 /** 1567 * Sets the file type to be transferred and the format. The type should be 1568 * one of <code> FTP.ASCII_FILE_TYPE </code>, 1569 * <code> FTP.BINARY_FILE_TYPE </code>, etc. The file type only needs to 1570 * be set when you want to change the type. After changing it, the new 1571 * type stays in effect until you change it again. The default file type 1572 * is <code> FTP.ASCII_FILE_TYPE </code> if this method is never called. 1573 * <br> 1574 * The server default is supposed to be ASCII (see RFC 959), however many 1575 * ftp servers default to BINARY. <b>To ensure correct operation with all servers, 1576 * always specify the appropriate file type after connecting to the server.</b> 1577 * <br> 1578 * The format should be one of the FTP class <code> TEXT_FORMAT </code> 1579 * constants, or if the type is <code> FTP.LOCAL_FILE_TYPE </code>, the 1580 * format should be the byte size for that type. The default format 1581 * is <code> FTP.NON_PRINT_TEXT_FORMAT </code> if this method is never 1582 * called. 1583 * <p> 1584 * <b>N.B.</b> currently calling any connect method will reset the type to 1585 * FTP.ASCII_FILE_TYPE and the formatOrByteSize to FTP.NON_PRINT_TEXT_FORMAT. 1586 * 1587 * @param fileType The <code> _FILE_TYPE </code> constant indicating the 1588 * type of file. 1589 * @param formatOrByteSize The format of the file (one of the 1590 * <code>_FORMAT</code> constants. In the case of 1591 * <code>LOCAL_FILE_TYPE</code>, the byte size. 1592 * 1593 * @return True if successfully completed, false if not. 1594 * @throws FTPConnectionClosedException 1595 * If the FTP server prematurely closes the connection as a result 1596 * of the client being idle or some other reason causing the server 1597 * to send FTP reply code 421. This exception may be caught either 1598 * as an IOException or independently as itself. 1599 * @throws IOException If an I/O error occurs while either sending a 1600 * command to the server or receiving a reply from the server. 1601 */ 1602 public boolean setFileType(final int fileType, final int formatOrByteSize) 1603 throws IOException 1604 { 1605 if (FTPReply.isPositiveCompletion(type(fileType, formatOrByteSize))) 1606 { 1607 this.fileType = fileType; 1608 this.fileFormat = formatOrByteSize; 1609 return true; 1610 } 1611 return false; 1612 } 1613 1614 1615 /** 1616 * Sets the file structure. The default structure is 1617 * <code> FTP.FILE_STRUCTURE </code> if this method is never called 1618 * or if a connect method is called. 1619 * 1620 * @param structure The structure of the file (one of the FTP class 1621 * <code>_STRUCTURE</code> constants). 1622 * @return True if successfully completed, false if not. 1623 * @throws FTPConnectionClosedException 1624 * If the FTP server prematurely closes the connection as a result 1625 * of the client being idle or some other reason causing the server 1626 * to send FTP reply code 421. This exception may be caught either 1627 * as an IOException or independently as itself. 1628 * @throws IOException If an I/O error occurs while either sending a 1629 * command to the server or receiving a reply from the server. 1630 */ 1631 public boolean setFileStructure(final int structure) throws IOException 1632 { 1633 if (FTPReply.isPositiveCompletion(stru(structure))) 1634 { 1635 fileStructure = structure; 1636 return true; 1637 } 1638 return false; 1639 } 1640 1641 1642 /** 1643 * Sets the transfer mode. The default transfer mode 1644 * <code> FTP.STREAM_TRANSFER_MODE </code> if this method is never called 1645 * or if a connect method is called. 1646 * 1647 * @param mode The new transfer mode to use (one of the FTP class 1648 * <code>_TRANSFER_MODE</code> constants). 1649 * @return True if successfully completed, false if not. 1650 * @throws FTPConnectionClosedException 1651 * If the FTP server prematurely closes the connection as a result 1652 * of the client being idle or some other reason causing the server 1653 * to send FTP reply code 421. This exception may be caught either 1654 * as an IOException or independently as itself. 1655 * @throws IOException If an I/O error occurs while either sending a 1656 * command to the server or receiving a reply from the server. 1657 */ 1658 public boolean setFileTransferMode(final int mode) throws IOException 1659 { 1660 if (FTPReply.isPositiveCompletion(mode(mode))) 1661 { 1662 fileTransferMode = mode; 1663 return true; 1664 } 1665 return false; 1666 } 1667 1668 1669 /** 1670 * Initiate a server to server file transfer. This method tells the 1671 * server to which the client is connected to retrieve a given file from 1672 * the other server. 1673 * 1674 * @param fileName The name of the file to retrieve. 1675 * @return True if successfully completed, false if not. 1676 * @throws FTPConnectionClosedException 1677 * If the FTP server prematurely closes the connection as a result 1678 * of the client being idle or some other reason causing the server 1679 * to send FTP reply code 421. This exception may be caught either 1680 * as an IOException or independently as itself. 1681 * @throws IOException If an I/O error occurs while either sending a 1682 * command to the server or receiving a reply from the server. 1683 */ 1684 public boolean remoteRetrieve(final String fileName) throws IOException 1685 { 1686 if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || 1687 dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { 1688 return FTPReply.isPositivePreliminary(retr(fileName)); 1689 } 1690 return false; 1691 } 1692 1693 1694 /** 1695 * Initiate a server to server file transfer. This method tells the 1696 * server to which the client is connected to store a file on 1697 * the other server using the given file name. The other server must 1698 * have had a <code> remoteRetrieve </code> issued to it by another 1699 * FTPClient. 1700 * 1701 * @param fileName The name to call the file that is to be stored. 1702 * @return True if successfully completed, false if not. 1703 * @throws FTPConnectionClosedException 1704 * If the FTP server prematurely closes the connection as a result 1705 * of the client being idle or some other reason causing the server 1706 * to send FTP reply code 421. This exception may be caught either 1707 * as an IOException or independently as itself. 1708 * @throws IOException If an I/O error occurs while either sending a 1709 * command to the server or receiving a reply from the server. 1710 */ 1711 public boolean remoteStore(final String fileName) throws IOException 1712 { 1713 if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || 1714 dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { 1715 return FTPReply.isPositivePreliminary(stor(fileName)); 1716 } 1717 return false; 1718 } 1719 1720 1721 /** 1722 * Initiate a server to server file transfer. This method tells the 1723 * server to which the client is connected to store a file on 1724 * the other server using a unique file name based on the given file name. 1725 * The other server must have had a <code> remoteRetrieve </code> issued 1726 * to it by another FTPClient. 1727 * 1728 * @param fileName The name on which to base the file name of the file 1729 * that is to be stored. 1730 * @return True if successfully completed, false if not. 1731 * @throws FTPConnectionClosedException 1732 * If the FTP server prematurely closes the connection as a result 1733 * of the client being idle or some other reason causing the server 1734 * to send FTP reply code 421. This exception may be caught either 1735 * as an IOException or independently as itself. 1736 * @throws IOException If an I/O error occurs while either sending a 1737 * command to the server or receiving a reply from the server. 1738 */ 1739 public boolean remoteStoreUnique(final String fileName) throws IOException 1740 { 1741 if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || 1742 dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { 1743 return FTPReply.isPositivePreliminary(stou(fileName)); 1744 } 1745 return false; 1746 } 1747 1748 1749 /** 1750 * Initiate a server to server file transfer. This method tells the 1751 * server to which the client is connected to store a file on 1752 * the other server using a unique file name. 1753 * The other server must have had a <code> remoteRetrieve </code> issued 1754 * to it by another FTPClient. Many FTP servers require that a base 1755 * file name be given from which the unique file name can be derived. For 1756 * those servers use the other version of <code> remoteStoreUnique</code> 1757 * 1758 * @return True if successfully completed, false if not. 1759 * @throws FTPConnectionClosedException 1760 * If the FTP server prematurely closes the connection as a result 1761 * of the client being idle or some other reason causing the server 1762 * to send FTP reply code 421. This exception may be caught either 1763 * as an IOException or independently as itself. 1764 * @throws IOException If an I/O error occurs while either sending a 1765 * command to the server or receiving a reply from the server. 1766 */ 1767 public boolean remoteStoreUnique() throws IOException 1768 { 1769 if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || 1770 dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { 1771 return FTPReply.isPositivePreliminary(stou()); 1772 } 1773 return false; 1774 } 1775 1776 // For server to server transfers 1777 /** 1778 * Initiate a server to server file transfer. This method tells the 1779 * server to which the client is connected to append to a given file on 1780 * the other server. The other server must have had a 1781 * <code> remoteRetrieve </code> issued to it by another FTPClient. 1782 * 1783 * @param fileName The name of the file to be appended to, or if the 1784 * file does not exist, the name to call the file being stored. 1785 * 1786 * @return True if successfully completed, false if not. 1787 * @throws FTPConnectionClosedException 1788 * If the FTP server prematurely closes the connection as a result 1789 * of the client being idle or some other reason causing the server 1790 * to send FTP reply code 421. This exception may be caught either 1791 * as an IOException or independently as itself. 1792 * @throws IOException If an I/O error occurs while either sending a 1793 * command to the server or receiving a reply from the server. 1794 */ 1795 public boolean remoteAppend(final String fileName) throws IOException 1796 { 1797 if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || 1798 dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { 1799 return FTPReply.isPositivePreliminary(appe(fileName)); 1800 } 1801 return false; 1802 } 1803 1804 /** 1805 * There are a few FTPClient methods that do not complete the 1806 * entire sequence of FTP commands to complete a transaction. These 1807 * commands require some action by the programmer after the reception 1808 * of a positive intermediate command. After the programmer's code 1809 * completes its actions, it must call this method to receive 1810 * the completion reply from the server and verify the success of the 1811 * entire transaction. 1812 * <p> 1813 * For example, 1814 * <pre> 1815 * InputStream input; 1816 * OutputStream output; 1817 * input = new FileInputStream("foobaz.txt"); 1818 * output = ftp.storeFileStream("foobar.txt") 1819 * if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) { 1820 * input.close(); 1821 * output.close(); 1822 * ftp.logout(); 1823 * ftp.disconnect(); 1824 * System.err.println("File transfer failed."); 1825 * System.exit(1); 1826 * } 1827 * Util.copyStream(input, output); 1828 * input.close(); 1829 * output.close(); 1830 * // Must call completePendingCommand() to finish command. 1831 * if(!ftp.completePendingCommand()) { 1832 * ftp.logout(); 1833 * ftp.disconnect(); 1834 * System.err.println("File transfer failed."); 1835 * System.exit(1); 1836 * } 1837 * </pre> 1838 * 1839 * @return True if successfully completed, false if not. 1840 * @throws FTPConnectionClosedException 1841 * If the FTP server prematurely closes the connection as a result 1842 * of the client being idle or some other reason causing the server 1843 * to send FTP reply code 421. This exception may be caught either 1844 * as an IOException or independently as itself. 1845 * @throws IOException If an I/O error occurs while either sending a 1846 * command to the server or receiving a reply from the server. 1847 */ 1848 public boolean completePendingCommand() throws IOException 1849 { 1850 return FTPReply.isPositiveCompletion(getReply()); 1851 } 1852 1853 1854 /** 1855 * Retrieves a named file from the server and writes it to the given 1856 * OutputStream. This method does NOT close the given OutputStream. 1857 * If the current file type is ASCII, line separators in the file are 1858 * converted to the local representation. 1859 * <p> 1860 * Note: if you have used {@link #setRestartOffset(long)}, 1861 * the file data will start from the selected offset. 1862 * @param remote The name of the remote file. 1863 * @param local The local OutputStream to which to write the file. 1864 * @return True if successfully completed, false if not. 1865 * @throws FTPConnectionClosedException 1866 * If the FTP server prematurely closes the connection as a result 1867 * of the client being idle or some other reason causing the server 1868 * to send FTP reply code 421. This exception may be caught either 1869 * as an IOException or independently as itself. 1870 * @throws org.apache.commons.net.io.CopyStreamException 1871 * If an I/O error occurs while actually 1872 * transferring the file. The CopyStreamException allows you to 1873 * determine the number of bytes transferred and the IOException 1874 * causing the error. This exception may be caught either 1875 * as an IOException or independently as itself. 1876 * @throws IOException If an I/O error occurs while either sending a 1877 * command to the server or receiving a reply from the server. 1878 */ 1879 public boolean retrieveFile(final String remote, final OutputStream local) 1880 throws IOException 1881 { 1882 return _retrieveFile(FTPCmd.RETR.getCommand(), remote, local); 1883 } 1884 1885 /** 1886 * @param command the command to get 1887 * @param remote the remote file name 1888 * @param local The local OutputStream to which to write the file. 1889 * @return true if successful 1890 * @throws IOException on error 1891 * @since 3.1 1892 */ 1893 protected boolean _retrieveFile(final String command, final String remote, final OutputStream local) 1894 throws IOException 1895 { 1896 final Socket socket = _openDataConnection_(command, remote); 1897 1898 if (socket == null) { 1899 return false; 1900 } 1901 1902 InputStream input = null; 1903 CSL csl = null; 1904 try { 1905 try { 1906 if (fileType == ASCII_FILE_TYPE) { 1907 input = new FromNetASCIIInputStream(getBufferedInputStream(socket.getInputStream())); 1908 } else { 1909 input = getBufferedInputStream(socket.getInputStream()); 1910 } 1911 1912 if (controlKeepAliveTimeout > 0) { 1913 csl = new CSL(this, controlKeepAliveTimeout, controlKeepAliveReplyTimeout); 1914 } 1915 1916 // Treat everything else as binary for now 1917 Util.copyStream(input, local, getBufferSize(), CopyStreamEvent.UNKNOWN_STREAM_SIZE, mergeListeners(csl), 1918 false); 1919 } finally { 1920 Util.closeQuietly(input); 1921 } 1922 // Get the transfer response 1923 return completePendingCommand(); 1924 } finally { 1925 Util.closeQuietly(socket); 1926 if (csl != null) { 1927 cslDebug = csl.cleanUp(); // fetch any outstanding keepalive replies 1928 } 1929 } 1930 } 1931 1932 /** 1933 * Returns an InputStream from which a named file from the server 1934 * can be read. If the current file type is ASCII, the returned 1935 * InputStream will convert line separators in the file to 1936 * the local representation. You must close the InputStream when you 1937 * finish reading from it. The InputStream itself will take care of 1938 * closing the parent data connection socket upon being closed. 1939 * <p> 1940 * <b>To finalize the file transfer you must call 1941 * {@link #completePendingCommand completePendingCommand } and 1942 * check its return value to verify success.</b> 1943 * If this is not done, subsequent commands may behave unexpectedly. 1944 * <p> 1945 * Note: if you have used {@link #setRestartOffset(long)}, 1946 * the file data will start from the selected offset. 1947 * 1948 * @param remote The name of the remote file. 1949 * @return An InputStream from which the remote file can be read. If 1950 * the data connection cannot be opened (e.g., the file does not 1951 * exist), null is returned (in which case you may check the reply 1952 * code to determine the exact reason for failure). 1953 * @throws FTPConnectionClosedException 1954 * If the FTP server prematurely closes the connection as a result 1955 * of the client being idle or some other reason causing the server 1956 * to send FTP reply code 421. This exception may be caught either 1957 * as an IOException or independently as itself. 1958 * @throws IOException If an I/O error occurs while either sending a 1959 * command to the server or receiving a reply from the server. 1960 */ 1961 public InputStream retrieveFileStream(final String remote) throws IOException 1962 { 1963 return _retrieveFileStream(FTPCmd.RETR.getCommand(), remote); 1964 } 1965 1966 /** 1967 * @param command the command to send 1968 * @param remote the remote file name 1969 * @return the stream from which to read the file 1970 * @throws IOException on error 1971 * @since 3.1 1972 */ 1973 protected InputStream _retrieveFileStream(final String command, final String remote) 1974 throws IOException 1975 { 1976 final Socket socket = _openDataConnection_(command, remote); 1977 1978 if (socket == null) { 1979 return null; 1980 } 1981 1982 final InputStream input; 1983 if (fileType == ASCII_FILE_TYPE) { 1984 // We buffer ascii transfers because the buffering has to 1985 // be interposed between FromNetASCIIOutputSream and the underlying 1986 // socket input stream. We don't buffer binary transfers 1987 // because we don't want to impose a buffering policy on the 1988 // programmer if possible. Programmers can decide on their 1989 // own if they want to wrap the SocketInputStream we return 1990 // for file types other than ASCII. 1991 input = new FromNetASCIIInputStream(getBufferedInputStream(socket.getInputStream())); 1992 } else { 1993 input = socket.getInputStream(); 1994 } 1995 return new org.apache.commons.net.io.SocketInputStream(socket, input); 1996 } 1997 1998 1999 /** 2000 * Stores a file on the server using the given name and taking input 2001 * from the given InputStream. This method does NOT close the given 2002 * InputStream. If the current file type is ASCII, line separators in 2003 * the file are transparently converted to the NETASCII format (i.e., 2004 * you should not attempt to create a special InputStream to do this). 2005 * 2006 * @param remote The name to give the remote file. 2007 * @param local The local InputStream from which to read the file. 2008 * @return True if successfully completed, false if not. 2009 * @throws FTPConnectionClosedException 2010 * If the FTP server prematurely closes the connection as a result 2011 * of the client being idle or some other reason causing the server 2012 * to send FTP reply code 421. This exception may be caught either 2013 * as an IOException or independently as itself. 2014 * @throws org.apache.commons.net.io.CopyStreamException 2015 * If an I/O error occurs while actually 2016 * transferring the file. The CopyStreamException allows you to 2017 * determine the number of bytes transferred and the IOException 2018 * causing the error. This exception may be caught either 2019 * as an IOException or independently as itself. 2020 * @throws IOException If an I/O error occurs while either sending a 2021 * command to the server or receiving a reply from the server. 2022 */ 2023 public boolean storeFile(final String remote, final InputStream local) 2024 throws IOException 2025 { 2026 return storeFile(FTPCmd.STOR, remote, local); 2027 } 2028 2029 2030 /** 2031 * Returns an OutputStream through which data can be written to store 2032 * a file on the server using the given name. If the current file type 2033 * is ASCII, the returned OutputStream will convert line separators in 2034 * the file to the NETASCII format (i.e., you should not attempt to 2035 * create a special OutputStream to do this). You must close the 2036 * OutputStream when you finish writing to it. The OutputStream itself 2037 * will take care of closing the parent data connection socket upon being 2038 * closed. 2039 * <p> 2040 * <b>To finalize the file transfer you must call 2041 * {@link #completePendingCommand completePendingCommand } and 2042 * check its return value to verify success.</b> 2043 * If this is not done, subsequent commands may behave unexpectedly. 2044 * 2045 * @param remote The name to give the remote file. 2046 * @return An OutputStream through which the remote file can be written. If 2047 * the data connection cannot be opened (e.g., the file does not 2048 * exist), null is returned (in which case you may check the reply 2049 * code to determine the exact reason for failure). 2050 * @throws FTPConnectionClosedException 2051 * If the FTP server prematurely closes the connection as a result 2052 * of the client being idle or some other reason causing the server 2053 * to send FTP reply code 421. This exception may be caught either 2054 * as an IOException or independently as itself. 2055 * @throws IOException If an I/O error occurs while either sending a 2056 * command to the server or receiving a reply from the server. 2057 */ 2058 public OutputStream storeFileStream(final String remote) throws IOException 2059 { 2060 return storeFileStream(FTPCmd.STOR, remote); 2061 } 2062 2063 /** 2064 * Appends to a file on the server with the given name, taking input 2065 * from the given InputStream. This method does NOT close the given 2066 * InputStream. If the current file type is ASCII, line separators in 2067 * the file are transparently converted to the NETASCII format (i.e., 2068 * you should not attempt to create a special InputStream to do this). 2069 * 2070 * @param remote The name of the remote file. 2071 * @param local The local InputStream from which to read the data to 2072 * be appended to the remote file. 2073 * @return True if successfully completed, false if not. 2074 * @throws FTPConnectionClosedException 2075 * If the FTP server prematurely closes the connection as a result 2076 * of the client being idle or some other reason causing the server 2077 * to send FTP reply code 421. This exception may be caught either 2078 * as an IOException or independently as itself. 2079 * @throws org.apache.commons.net.io.CopyStreamException 2080 * If an I/O error occurs while actually 2081 * transferring the file. The CopyStreamException allows you to 2082 * determine the number of bytes transferred and the IOException 2083 * causing the error. This exception may be caught either 2084 * as an IOException or independently as itself. 2085 * @throws IOException If an I/O error occurs while either sending a 2086 * command to the server or receiving a reply from the server. 2087 */ 2088 public boolean appendFile(final String remote, final InputStream local) 2089 throws IOException 2090 { 2091 return storeFile(FTPCmd.APPE, remote, local); 2092 } 2093 2094 /** 2095 * Returns an OutputStream through which data can be written to append 2096 * to a file on the server with the given name. If the current file type 2097 * is ASCII, the returned OutputStream will convert line separators in 2098 * the file to the NETASCII format (i.e., you should not attempt to 2099 * create a special OutputStream to do this). You must close the 2100 * OutputStream when you finish writing to it. The OutputStream itself 2101 * will take care of closing the parent data connection socket upon being 2102 * closed. 2103 * <p> 2104 * <b>To finalize the file transfer you must call 2105 * {@link #completePendingCommand completePendingCommand } and 2106 * check its return value to verify success.</b> 2107 * If this is not done, subsequent commands may behave unexpectedly. 2108 * 2109 * @param remote The name of the remote file. 2110 * @return An OutputStream through which the remote file can be appended. 2111 * If the data connection cannot be opened (e.g., the file does not 2112 * exist), null is returned (in which case you may check the reply 2113 * code to determine the exact reason for failure). 2114 * @throws FTPConnectionClosedException 2115 * If the FTP server prematurely closes the connection as a result 2116 * of the client being idle or some other reason causing the server 2117 * to send FTP reply code 421. This exception may be caught either 2118 * as an IOException or independently as itself. 2119 * @throws IOException If an I/O error occurs while either sending a 2120 * command to the server or receiving a reply from the server. 2121 */ 2122 public OutputStream appendFileStream(final String remote) throws IOException 2123 { 2124 return storeFileStream(FTPCmd.APPE, remote); 2125 } 2126 2127 /** 2128 * Stores a file on the server using a unique name derived from the 2129 * given name and taking input 2130 * from the given InputStream. This method does NOT close the given 2131 * InputStream. If the current file type is ASCII, line separators in 2132 * the file are transparently converted to the NETASCII format (i.e., 2133 * you should not attempt to create a special InputStream to do this). 2134 * 2135 * @param remote The name on which to base the unique name given to 2136 * the remote file. 2137 * @param local The local InputStream from which to read the file. 2138 * @return True if successfully completed, false if not. 2139 * @throws FTPConnectionClosedException 2140 * If the FTP server prematurely closes the connection as a result 2141 * of the client being idle or some other reason causing the server 2142 * to send FTP reply code 421. This exception may be caught either 2143 * as an IOException or independently as itself. 2144 * @throws org.apache.commons.net.io.CopyStreamException 2145 * If an I/O error occurs while actually 2146 * transferring the file. The CopyStreamException allows you to 2147 * determine the number of bytes transferred and the IOException 2148 * causing the error. This exception may be caught either 2149 * as an IOException or independently as itself. 2150 * @throws IOException If an I/O error occurs while either sending a 2151 * command to the server or receiving a reply from the server. 2152 */ 2153 public boolean storeUniqueFile(final String remote, final InputStream local) 2154 throws IOException 2155 { 2156 return storeFile(FTPCmd.STOU, remote, local); 2157 } 2158 2159 2160 /** 2161 * Returns an OutputStream through which data can be written to store 2162 * a file on the server using a unique name derived from the given name. 2163 * If the current file type 2164 * is ASCII, the returned OutputStream will convert line separators in 2165 * the file to the NETASCII format (i.e., you should not attempt to 2166 * create a special OutputStream to do this). You must close the 2167 * OutputStream when you finish writing to it. The OutputStream itself 2168 * will take care of closing the parent data connection socket upon being 2169 * closed. 2170 * <p> 2171 * <b>To finalize the file transfer you must call 2172 * {@link #completePendingCommand completePendingCommand } and 2173 * check its return value to verify success.</b> 2174 * If this is not done, subsequent commands may behave unexpectedly. 2175 * 2176 * @param remote The name on which to base the unique name given to 2177 * the remote file. 2178 * @return An OutputStream through which the remote file can be written. If 2179 * the data connection cannot be opened (e.g., the file does not 2180 * exist), null is returned (in which case you may check the reply 2181 * code to determine the exact reason for failure). 2182 * @throws FTPConnectionClosedException 2183 * If the FTP server prematurely closes the connection as a result 2184 * of the client being idle or some other reason causing the server 2185 * to send FTP reply code 421. This exception may be caught either 2186 * as an IOException or independently as itself. 2187 * @throws IOException If an I/O error occurs while either sending a 2188 * command to the server or receiving a reply from the server. 2189 */ 2190 public OutputStream storeUniqueFileStream(final String remote) throws IOException 2191 { 2192 return storeFileStream(FTPCmd.STOU, remote); 2193 } 2194 2195 /** 2196 * Stores a file on the server using a unique name assigned by the 2197 * server and taking input from the given InputStream. This method does 2198 * NOT close the given 2199 * InputStream. If the current file type is ASCII, line separators in 2200 * the file are transparently converted to the NETASCII format (i.e., 2201 * you should not attempt to create a special InputStream to do this). 2202 * 2203 * @param local The local InputStream from which to read the file. 2204 * @return True if successfully completed, false if not. 2205 * @throws FTPConnectionClosedException 2206 * If the FTP server prematurely closes the connection as a result 2207 * of the client being idle or some other reason causing the server 2208 * to send FTP reply code 421. This exception may be caught either 2209 * as an IOException or independently as itself. 2210 * @throws org.apache.commons.net.io.CopyStreamException 2211 * If an I/O error occurs while actually 2212 * transferring the file. The CopyStreamException allows you to 2213 * determine the number of bytes transferred and the IOException 2214 * causing the error. This exception may be caught either 2215 * as an IOException or independently as itself. 2216 * @throws IOException If an I/O error occurs while either sending a 2217 * command to the server or receiving a reply from the server. 2218 */ 2219 public boolean storeUniqueFile(final InputStream local) throws IOException 2220 { 2221 return storeFile(FTPCmd.STOU, null, local); 2222 } 2223 2224 /** 2225 * Returns an OutputStream through which data can be written to store 2226 * a file on the server using a unique name assigned by the server. 2227 * If the current file type 2228 * is ASCII, the returned OutputStream will convert line separators in 2229 * the file to the NETASCII format (i.e., you should not attempt to 2230 * create a special OutputStream to do this). You must close the 2231 * OutputStream when you finish writing to it. The OutputStream itself 2232 * will take care of closing the parent data connection socket upon being 2233 * closed. 2234 * <p> 2235 * <b>To finalize the file transfer you must call 2236 * {@link #completePendingCommand completePendingCommand } and 2237 * check its return value to verify success.</b> 2238 * If this is not done, subsequent commands may behave unexpectedly. 2239 * 2240 * @return An OutputStream through which the remote file can be written. If 2241 * the data connection cannot be opened (e.g., the file does not 2242 * exist), null is returned (in which case you may check the reply 2243 * code to determine the exact reason for failure). 2244 * @throws FTPConnectionClosedException 2245 * If the FTP server prematurely closes the connection as a result 2246 * of the client being idle or some other reason causing the server 2247 * to send FTP reply code 421. This exception may be caught either 2248 * as an IOException or independently as itself. 2249 * @throws IOException If an I/O error occurs while either sending a 2250 * command to the server or receiving a reply from the server. 2251 */ 2252 public OutputStream storeUniqueFileStream() throws IOException 2253 { 2254 return storeFileStream(FTPCmd.STOU, null); 2255 } 2256 2257 /** 2258 * Reserve a number of bytes on the server for the next file transfer. 2259 * 2260 * @param bytes The number of bytes which the server should allocate. 2261 * @return True if successfully completed, false if not. 2262 * @throws FTPConnectionClosedException 2263 * If the FTP server prematurely closes the connection as a result 2264 * of the client being idle or some other reason causing the server 2265 * to send FTP reply code 421. This exception may be caught either 2266 * as an IOException or independently as itself. 2267 * @throws IOException If an I/O error occurs while either sending a 2268 * command to the server or receiving a reply from the server. 2269 */ 2270 public boolean allocate(final int bytes) throws IOException 2271 { 2272 return FTPReply.isPositiveCompletion(allo(bytes)); 2273 } 2274 2275 /** 2276 * Reserve a number of bytes on the server for the next file transfer. 2277 * 2278 * @param bytes The number of bytes which the server should allocate. 2279 * @return True if successfully completed, false if not. 2280 * @throws FTPConnectionClosedException 2281 * If the FTP server prematurely closes the connection as a result 2282 * of the client being idle or some other reason causing the server 2283 * to send FTP reply code 421. This exception may be caught either 2284 * as an IOException or independently as itself. 2285 * @throws IOException If an I/O error occurs while either sending a 2286 * command to the server or receiving a reply from the server. 2287 */ 2288 public boolean allocate(final long bytes) throws IOException 2289 { 2290 return FTPReply.isPositiveCompletion(allo(bytes)); 2291 } 2292 2293 /** 2294 * Query the server for supported features. The server may reply with a list of server-supported exensions. 2295 * For example, a typical client-server interaction might be (from RFC 2389): 2296 * <pre> 2297 C> feat 2298 S> 211-Extensions supported: 2299 S> MLST size*;create;modify*;perm;media-type 2300 S> SIZE 2301 S> COMPRESSION 2302 S> MDTM 2303 S> 211 END 2304 * </pre> 2305 * @see <a href="http://www.faqs.org/rfcs/rfc2389.html">http://www.faqs.org/rfcs/rfc2389.html</a> 2306 * @return True if successfully completed, false if not. 2307 * @throws IOException on error 2308 * @since 2.2 2309 */ 2310 public boolean features() throws IOException { 2311 return FTPReply.isPositiveCompletion(feat()); 2312 } 2313 2314 /** 2315 * Query the server for a supported feature, and returns its values (if any). 2316 * Caches the parsed response to avoid resending the command repeatedly. 2317 * @param feature the feature to check 2318 * 2319 * @return if the feature is present, returns the feature values (empty array if none) 2320 * Returns {@code null} if the feature is not found or the command failed. 2321 * Check {@link #getReplyCode()} or {@link #getReplyString()} if so. 2322 * @throws IOException on error 2323 * @since 3.0 2324 */ 2325 public String[] featureValues(final String feature) throws IOException { 2326 if (!initFeatureMap()) { 2327 return null; 2328 } 2329 final Set<String> entries = featuresMap.get(feature.toUpperCase(Locale.ENGLISH)); 2330 if (entries != null) { 2331 return entries.toArray(new String[entries.size()]); 2332 } 2333 return null; 2334 } 2335 2336 /** 2337 * Query the server for a supported feature, and returns the its value (if any). 2338 * Caches the parsed response to avoid resending the command repeatedly. 2339 * @param feature the feature to check 2340 * 2341 * @return if the feature is present, returns the feature value or the empty string 2342 * if the feature exists but has no value. 2343 * Returns {@code null} if the feature is not found or the command failed. 2344 * Check {@link #getReplyCode()} or {@link #getReplyString()} if so. 2345 * @throws IOException on error 2346 * @since 3.0 2347 */ 2348 public String featureValue(final String feature) throws IOException { 2349 final String [] values = featureValues(feature); 2350 if (values != null) { 2351 return values[0]; 2352 } 2353 return null; 2354 } 2355 2356 /** 2357 * Query the server for a supported feature. 2358 * Caches the parsed response to avoid resending the command repeatedly. 2359 * 2360 * @param feature the name of the feature; it is converted to upper case. 2361 * @return {@code true} if the feature is present, {@code false} if the feature is not present 2362 * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()} 2363 * if it is necessary to distinguish these cases. 2364 * 2365 * @throws IOException on error 2366 * @since 3.0 2367 */ 2368 public boolean hasFeature(final String feature) throws IOException { 2369 if (!initFeatureMap()) { 2370 return false; 2371 } 2372 return featuresMap.containsKey(feature.toUpperCase(Locale.ENGLISH)); 2373 } 2374 2375 /** 2376 * Query the server for a supported feature with particular value, 2377 * for example "AUTH SSL" or "AUTH TLS". 2378 * Caches the parsed response to avoid resending the command repeatedly. 2379 * 2380 * @param feature the name of the feature; it is converted to upper case. 2381 * @param value the value to find. 2382 * 2383 * @return {@code true} if the feature is present, {@code false} if the feature is not present 2384 * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()} 2385 * if it is necessary to distinguish these cases. 2386 * 2387 * @throws IOException on error 2388 * @since 3.0 2389 */ 2390 public boolean hasFeature(final String feature, final String value) throws IOException { 2391 if (!initFeatureMap()) { 2392 return false; 2393 } 2394 final Set<String> entries = featuresMap.get(feature.toUpperCase(Locale.ENGLISH)); 2395 if (entries != null) { 2396 return entries.contains(value); 2397 } 2398 return false; 2399 } 2400 2401 /* 2402 * Create the feature map if not already created. 2403 */ 2404 private boolean initFeatureMap() throws IOException { 2405 if (featuresMap == null) { 2406 // Don't create map here, because next line may throw exception 2407 final int replyCode = feat(); 2408 if (replyCode == FTPReply.NOT_LOGGED_IN) { // 503 2409 return false; // NET-518; don't create empy map 2410 } 2411 final boolean success = FTPReply.isPositiveCompletion(replyCode); 2412 // we init the map here, so we don't keep trying if we know the command will fail 2413 featuresMap = new HashMap<>(); 2414 if (!success) { 2415 return false; 2416 } 2417 for (final String l : getReplyStrings()) { 2418 if (l.startsWith(" ")) { // it's a FEAT entry 2419 String key; 2420 String value=""; 2421 final int varsep = l.indexOf(' ', 1); 2422 if (varsep > 0) { 2423 key = l.substring(1, varsep); 2424 value = l.substring(varsep+1); 2425 } else { 2426 key = l.substring(1); 2427 } 2428 key = key.toUpperCase(Locale.ENGLISH); 2429 Set<String> entries = featuresMap.get(key); 2430 if (entries == null) { 2431 entries = new HashSet<>(); 2432 featuresMap.put(key, entries); 2433 } 2434 entries.add(value); 2435 } 2436 } 2437 } 2438 return true; 2439 } 2440 2441 /** 2442 * Reserve space on the server for the next file transfer. 2443 * 2444 * @param bytes The number of bytes which the server should allocate. 2445 * @param recordSize The size of a file record. 2446 * @return True if successfully completed, false if not. 2447 * @throws FTPConnectionClosedException 2448 * If the FTP server prematurely closes the connection as a result 2449 * of the client being idle or some other reason causing the server 2450 * to send FTP reply code 421. This exception may be caught either 2451 * as an IOException or independently as itself. 2452 * @throws IOException If an I/O error occurs while either sending a 2453 * command to the server or receiving a reply from the server. 2454 */ 2455 public boolean allocate(final int bytes, final int recordSize) throws IOException 2456 { 2457 return FTPReply.isPositiveCompletion(allo(bytes, recordSize)); 2458 } 2459 2460 /** 2461 * Reserve space on the server for the next file transfer. 2462 * 2463 * @param bytes The number of bytes which the server should allocate. 2464 * @param recordSize The size of a file record. 2465 * @return True if successfully completed, false if not. 2466 * @throws FTPConnectionClosedException 2467 * If the FTP server prematurely closes the connection as a result 2468 * of the client being idle or some other reason causing the server 2469 * to send FTP reply code 421. This exception may be caught either 2470 * as an IOException or independently as itself. 2471 * @throws IOException If an I/O error occurs while either sending a 2472 * command to the server or receiving a reply from the server. 2473 */ 2474 public boolean allocate(final long bytes, final int recordSize) throws IOException 2475 { 2476 return FTPReply.isPositiveCompletion(allo(bytes, recordSize)); 2477 } 2478 2479 2480 /** 2481 * Issue a command and wait for the reply. 2482 * <p> 2483 * Should only be used with commands that return replies on the 2484 * command channel - do not use for LIST, NLST, MLSD etc. 2485 * 2486 * @param command The command to invoke 2487 * @param params The parameters string, may be {@code null} 2488 * @return True if successfully completed, false if not, in which case 2489 * call {@link #getReplyCode()} or {@link #getReplyString()} 2490 * to get the reason. 2491 * 2492 * @throws IOException If an I/O error occurs while either sending a 2493 * command to the server or receiving a reply from the server. 2494 * @since 3.0 2495 */ 2496 public boolean doCommand(final String command, final String params) throws IOException 2497 { 2498 return FTPReply.isPositiveCompletion(sendCommand(command, params)); 2499 } 2500 2501 /** 2502 * Issue a command and wait for the reply, returning it as an array of strings. 2503 * <p> 2504 * Should only be used with commands that return replies on the 2505 * command channel - do not use for LIST, NLST, MLSD etc. 2506 * 2507 * @param command The command to invoke 2508 * @param params The parameters string, may be {@code null} 2509 * @return The array of replies, or {@code null} if the command failed, in which case 2510 * call {@link #getReplyCode()} or {@link #getReplyString()} 2511 * to get the reason. 2512 * 2513 * @throws IOException If an I/O error occurs while either sending a 2514 * command to the server or receiving a reply from the server. 2515 * @since 3.0 2516 */ 2517 public String[] doCommandAsStrings(final String command, final String params) throws IOException 2518 { 2519 final boolean success = FTPReply.isPositiveCompletion(sendCommand(command, params)); 2520 if (success){ 2521 return getReplyStrings(); 2522 } 2523 return null; 2524 } 2525 2526 /** 2527 * Get file details using the MLST command 2528 * 2529 * @param pathname the file or directory to list, may be {@code null} 2530 * @return the file details, may be {@code null} 2531 * @throws IOException on error 2532 * @since 3.0 2533 */ 2534 public FTPFile mlistFile(final String pathname) throws IOException 2535 { 2536 final boolean success = FTPReply.isPositiveCompletion(sendCommand(FTPCmd.MLST, pathname)); 2537 if (success){ 2538 String reply = getReplyStrings()[1]; 2539 // some FTP server reply not contains space before fact(s) 2540 if(reply.charAt(0) != ' ') { reply = " " + reply; } 2541 /* check the response makes sense. 2542 * Must have space before fact(s) and between fact(s) and file name 2543 * Fact(s) can be absent, so at least 3 chars are needed. 2544 */ 2545 if (reply.length() < 3) { 2546 throw new MalformedServerReplyException("Invalid server reply (MLST): '" + reply + "'"); 2547 } 2548 // some FTP server reply contains more than one space before fact(s) 2549 final String entry = reply.replaceAll("^\\s+", ""); // skip leading space for parser 2550 return MLSxEntryParser.parseEntry(entry); 2551 } 2552 return null; 2553 } 2554 2555 /** 2556 * Generate a directory listing for the current directory using the MLSD command. 2557 * 2558 * @return the array of file entries 2559 * @throws IOException on error 2560 * @since 3.0 2561 */ 2562 public FTPFile[] mlistDir() throws IOException 2563 { 2564 return mlistDir(null); 2565 } 2566 2567 /** 2568 * Generate a directory listing using the MLSD command. 2569 * 2570 * @param pathname the directory name, may be {@code null} 2571 * @return the array of file entries 2572 * @throws IOException on error 2573 * @since 3.0 2574 */ 2575 public FTPFile[] mlistDir(final String pathname) throws IOException 2576 { 2577 final FTPListParseEngine engine = initiateMListParsing( pathname); 2578 return engine.getFiles(); 2579 } 2580 2581 /** 2582 * Generate a directory listing using the MLSD command. 2583 * 2584 * @param pathname the directory name, may be {@code null} 2585 * @param filter the filter to apply to the responses 2586 * @return the array of file entries 2587 * @throws IOException on error 2588 * @since 3.0 2589 */ 2590 public FTPFile[] mlistDir(final String pathname, final FTPFileFilter filter) throws IOException 2591 { 2592 final FTPListParseEngine engine = initiateMListParsing( pathname); 2593 return engine.getFiles(filter); 2594 } 2595 2596 /** 2597 * Restart a <code>STREAM_TRANSFER_MODE</code> file transfer starting 2598 * from the given offset. This will only work on FTP servers supporting 2599 * the REST comand for the stream transfer mode. However, most FTP 2600 * servers support this. Any subsequent file transfer will start 2601 * reading or writing the remote file from the indicated offset. 2602 * 2603 * @param offset The offset into the remote file at which to start the 2604 * next file transfer. 2605 * @return True if successfully completed, false if not. 2606 * @throws FTPConnectionClosedException 2607 * If the FTP server prematurely closes the connection as a result 2608 * of the client being idle or some other reason causing the server 2609 * to send FTP reply code 421. This exception may be caught either 2610 * as an IOException or independently as itself. 2611 * @throws IOException If an I/O error occurs while either sending a 2612 * command to the server or receiving a reply from the server. 2613 * @since 3.1 (changed from private to protected) 2614 */ 2615 protected boolean restart(final long offset) throws IOException 2616 { 2617 restartOffset = 0; 2618 return FTPReply.isPositiveIntermediate(rest(Long.toString(offset))); 2619 } 2620 2621 /** 2622 * Sets the restart offset for file transfers. 2623 * <p> 2624 * The restart command is not sent to the server immediately. 2625 * It is sent when a data connection is created as part of a 2626 * subsequent command. 2627 * The restart marker is reset to zero after use. 2628 * </p> 2629 * <p> 2630 * <b>Note: This method should only be invoked immediately prior to 2631 * the transfer to which it applies.</b> 2632 * 2633 * @param offset The offset into the remote file at which to start the 2634 * next file transfer. This must be a value greater than or 2635 * equal to zero. 2636 */ 2637 public void setRestartOffset(final long offset) 2638 { 2639 if (offset >= 0) { 2640 restartOffset = offset; 2641 } 2642 } 2643 2644 /** 2645 * Fetches the restart offset. 2646 * 2647 * @return offset The offset into the remote file at which to start the 2648 * next file transfer. 2649 */ 2650 public long getRestartOffset() 2651 { 2652 return restartOffset; 2653 } 2654 2655 2656 2657 /** 2658 * Renames a remote file. 2659 * 2660 * @param from The name of the remote file to rename. 2661 * @param to The new name of the remote file. 2662 * @return True if successfully completed, false if not. 2663 * @throws FTPConnectionClosedException 2664 * If the FTP server prematurely closes the connection as a result 2665 * of the client being idle or some other reason causing the server 2666 * to send FTP reply code 421. This exception may be caught either 2667 * as an IOException or independently as itself. 2668 * @throws IOException If an I/O error occurs while either sending a 2669 * command to the server or receiving a reply from the server. 2670 */ 2671 public boolean rename(final String from, final String to) throws IOException 2672 { 2673 if (!FTPReply.isPositiveIntermediate(rnfr(from))) { 2674 return false; 2675 } 2676 2677 return FTPReply.isPositiveCompletion(rnto(to)); 2678 } 2679 2680 2681 /** 2682 * Abort a transfer in progress. 2683 * 2684 * @return True if successfully completed, false if not. 2685 * @throws FTPConnectionClosedException 2686 * If the FTP server prematurely closes the connection as a result 2687 * of the client being idle or some other reason causing the server 2688 * to send FTP reply code 421. This exception may be caught either 2689 * as an IOException or independently as itself. 2690 * @throws IOException If an I/O error occurs while either sending a 2691 * command to the server or receiving a reply from the server. 2692 */ 2693 public boolean abort() throws IOException 2694 { 2695 return FTPReply.isPositiveCompletion(abor()); 2696 } 2697 2698 /** 2699 * Deletes a file on the FTP server. 2700 * 2701 * @param pathname The pathname of the file to be deleted. 2702 * @return True if successfully completed, false if not. 2703 * @throws FTPConnectionClosedException 2704 * If the FTP server prematurely closes the connection as a result 2705 * of the client being idle or some other reason causing the server 2706 * to send FTP reply code 421. This exception may be caught either 2707 * as an IOException or independently as itself. 2708 * @throws IOException If an I/O error occurs while either sending a 2709 * command to the server or receiving a reply from the server. 2710 */ 2711 public boolean deleteFile(final String pathname) throws IOException 2712 { 2713 return FTPReply.isPositiveCompletion(dele(pathname)); 2714 } 2715 2716 2717 /** 2718 * Removes a directory on the FTP server (if empty). 2719 * 2720 * @param pathname The pathname of the directory to remove. 2721 * @return True if successfully completed, false if not. 2722 * @throws FTPConnectionClosedException 2723 * If the FTP server prematurely closes the connection as a result 2724 * of the client being idle or some other reason causing the server 2725 * to send FTP reply code 421. This exception may be caught either 2726 * as an IOException or independently as itself. 2727 * @throws IOException If an I/O error occurs while either sending a 2728 * command to the server or receiving a reply from the server. 2729 */ 2730 public boolean removeDirectory(final String pathname) throws IOException 2731 { 2732 return FTPReply.isPositiveCompletion(rmd(pathname)); 2733 } 2734 2735 2736 /** 2737 * Creates a new subdirectory on the FTP server in the current directory 2738 * (if a relative pathname is given) or where specified (if an absolute 2739 * pathname is given). 2740 * 2741 * @param pathname The pathname of the directory to create. 2742 * @return True if successfully completed, false if not. 2743 * @throws FTPConnectionClosedException 2744 * If the FTP server prematurely closes the connection as a result 2745 * of the client being idle or some other reason causing the server 2746 * to send FTP reply code 421. This exception may be caught either 2747 * as an IOException or independently as itself. 2748 * @throws IOException If an I/O error occurs while either sending a 2749 * command to the server or receiving a reply from the server. 2750 */ 2751 public boolean makeDirectory(final String pathname) throws IOException 2752 { 2753 return FTPReply.isPositiveCompletion(mkd(pathname)); 2754 } 2755 2756 2757 /** 2758 * Returns the pathname of the current working directory. 2759 * 2760 * @return The pathname of the current working directory. If it cannot 2761 * be obtained, returns null. 2762 * @throws FTPConnectionClosedException 2763 * If the FTP server prematurely closes the connection as a result 2764 * of the client being idle or some other reason causing the server 2765 * to send FTP reply code 421. This exception may be caught either 2766 * as an IOException or independently as itself. 2767 * @throws IOException If an I/O error occurs while either sending a 2768 * command to the server or receiving a reply from the server. 2769 */ 2770 public String printWorkingDirectory() throws IOException 2771 { 2772 if (pwd() != FTPReply.PATHNAME_CREATED) { 2773 return null; 2774 } 2775 2776 return parsePathname(_replyLines.get( _replyLines.size() - 1)); 2777 } 2778 2779 2780 /** 2781 * Send a site specific command. 2782 * @param arguments The site specific command and arguments. 2783 * @return True if successfully completed, false if not. 2784 * @throws FTPConnectionClosedException 2785 * If the FTP server prematurely closes the connection as a result 2786 * of the client being idle or some other reason causing the server 2787 * to send FTP reply code 421. This exception may be caught either 2788 * as an IOException or independently as itself. 2789 * @throws IOException If an I/O error occurs while either sending a 2790 * command to the server or receiving a reply from the server. 2791 */ 2792 public boolean sendSiteCommand(final String arguments) throws IOException 2793 { 2794 return FTPReply.isPositiveCompletion(site(arguments)); 2795 } 2796 2797 2798 /** 2799 * Fetches the system type from the server and returns the string. 2800 * This value is cached for the duration of the connection after the 2801 * first call to this method. In other words, only the first time 2802 * that you invoke this method will it issue a SYST command to the 2803 * FTP server. FTPClient will remember the value and return the 2804 * cached value until a call to disconnect. 2805 * <p> 2806 * If the SYST command fails, and the system property 2807 * {@link #FTP_SYSTEM_TYPE_DEFAULT} is defined, then this is used instead. 2808 * @return The system type obtained from the server. Never null. 2809 * @throws FTPConnectionClosedException 2810 * If the FTP server prematurely closes the connection as a result 2811 * of the client being idle or some other reason causing the server 2812 * to send FTP reply code 421. This exception may be caught either 2813 * as an IOException or independently as itself. 2814 * @throws IOException If an I/O error occurs while either sending a 2815 * command to the server or receiving a reply from the server (and the default 2816 * system type property is not defined) 2817 * @since 2.2 2818 */ 2819 public String getSystemType() throws IOException 2820 { 2821 //if (syst() == FTPReply.NAME_SYSTEM_TYPE) 2822 // Technically, we should expect a NAME_SYSTEM_TYPE response, but 2823 // in practice FTP servers deviate, so we soften the condition to 2824 // a positive completion. 2825 if (systemName == null){ 2826 if (FTPReply.isPositiveCompletion(syst())) { 2827 // Assume that response is not empty here (cannot be null) 2828 systemName = _replyLines.get(_replyLines.size() - 1).substring(4); 2829 } else { 2830 // Check if the user has provided a default for when the SYST command fails 2831 final String systDefault = System.getProperty(FTP_SYSTEM_TYPE_DEFAULT); 2832 if (systDefault != null) { 2833 systemName = systDefault; 2834 } else { 2835 throw new IOException("Unable to determine system type - response: " + getReplyString()); 2836 } 2837 } 2838 } 2839 return systemName; 2840 } 2841 2842 2843 /** 2844 * Fetches the system help information from the server and returns the 2845 * full string. 2846 * 2847 * @return The system help string obtained from the server. null if the 2848 * information could not be obtained. 2849 * @throws FTPConnectionClosedException 2850 * If the FTP server prematurely closes the connection as a result 2851 * of the client being idle or some other reason causing the server 2852 * to send FTP reply code 421. This exception may be caught either 2853 * as an IOException or independently as itself. 2854 * @throws IOException If an I/O error occurs while either sending a 2855 * command to the server or receiving a reply from the server. 2856 */ 2857 public String listHelp() throws IOException 2858 { 2859 if (FTPReply.isPositiveCompletion(help())) { 2860 return getReplyString(); 2861 } 2862 return null; 2863 } 2864 2865 2866 /** 2867 * Fetches the help information for a given command from the server and 2868 * returns the full string. 2869 * @param command The command on which to ask for help. 2870 * @return The command help string obtained from the server. null if the 2871 * information could not be obtained. 2872 * @throws FTPConnectionClosedException 2873 * If the FTP server prematurely closes the connection as a result 2874 * of the client being idle or some other reason causing the server 2875 * to send FTP reply code 421. This exception may be caught either 2876 * as an IOException or independently as itself. 2877 * @throws IOException If an I/O error occurs while either sending a 2878 * command to the server or receiving a reply from the server. 2879 */ 2880 public String listHelp(final String command) throws IOException 2881 { 2882 if (FTPReply.isPositiveCompletion(help(command))) { 2883 return getReplyString(); 2884 } 2885 return null; 2886 } 2887 2888 2889 /** 2890 * Sends a NOOP command to the FTP server. This is useful for preventing 2891 * server timeouts. 2892 * 2893 * @return True if successfully completed, false if not. 2894 * @throws FTPConnectionClosedException 2895 * If the FTP server prematurely closes the connection as a result 2896 * of the client being idle or some other reason causing the server 2897 * to send FTP reply code 421. This exception may be caught either 2898 * as an IOException or independently as itself. 2899 * @throws IOException If an I/O error occurs while either sending a 2900 * command to the server or receiving a reply from the server. 2901 */ 2902 public boolean sendNoOp() throws IOException 2903 { 2904 return FTPReply.isPositiveCompletion(noop()); 2905 } 2906 2907 2908 /** 2909 * Obtain a list of file names in a directory (or just the name of a given 2910 * file, which is not particularly useful). This information is obtained 2911 * through the NLST command. If the given pathname is a directory and 2912 * contains no files, a zero length array is returned only 2913 * if the FTP server returned a positive completion code, otherwise 2914 * null is returned (the FTP server returned a 550 error No files found.). 2915 * If the directory is not empty, an array of file names in the directory is 2916 * returned. If the pathname corresponds 2917 * to a file, only that file will be listed. The server may or may not 2918 * expand glob expressions. 2919 * 2920 * @param pathname The file or directory to list. 2921 * Warning: the server may treat a leading '-' as an 2922 * option introducer. If so, try using an absolute path, 2923 * or prefix the path with ./ (unix style servers). 2924 * Some servers may support "--" as meaning end of options, 2925 * in which case "-- -xyz" should work. 2926 * @return The list of file names contained in the given path. null if 2927 * the list could not be obtained. If there are no file names in 2928 * the directory, a zero-length array is returned. 2929 * @throws FTPConnectionClosedException 2930 * If the FTP server prematurely closes the connection as a result 2931 * of the client being idle or some other reason causing the server 2932 * to send FTP reply code 421. This exception may be caught either 2933 * as an IOException or independently as itself. 2934 * @throws IOException If an I/O error occurs while either sending a 2935 * command to the server or receiving a reply from the server. 2936 */ 2937 public String[] listNames(final String pathname) throws IOException 2938 { 2939 final ArrayList<String> results = new ArrayList<>(); 2940 try (final Socket socket = _openDataConnection_(FTPCmd.NLST, getListArguments(pathname))) { 2941 2942 if (socket == null) { 2943 return null; 2944 } 2945 2946 try (final BufferedReader reader = new BufferedReader( 2947 new InputStreamReader(socket.getInputStream(), getControlEncoding()))) { 2948 2949 String line; 2950 while ((line = reader.readLine()) != null) { 2951 results.add(line); 2952 } 2953 } 2954 } 2955 2956 if (completePendingCommand()) { 2957 final String[] names = new String[results.size()]; 2958 return results.toArray(names); 2959 } 2960 2961 return null; 2962 } 2963 2964 2965 /** 2966 * Obtain a list of file names in the current working directory 2967 * This information is obtained through the NLST command. If the current 2968 * directory contains no files, a zero length array is returned only 2969 * if the FTP server returned a positive completion code, otherwise, 2970 * null is returned (the FTP server returned a 550 error No files found.). 2971 * If the directory is not empty, an array of file names in the directory is 2972 * returned. 2973 * 2974 * @return The list of file names contained in the current working 2975 * directory. null if the list could not be obtained. 2976 * If there are no file names in the directory, a zero-length array 2977 * is returned. 2978 * @throws FTPConnectionClosedException 2979 * If the FTP server prematurely closes the connection as a result 2980 * of the client being idle or some other reason causing the server 2981 * to send FTP reply code 421. This exception may be caught either 2982 * as an IOException or independently as itself. 2983 * @throws IOException If an I/O error occurs while either sending a 2984 * command to the server or receiving a reply from the server. 2985 */ 2986 public String[] listNames() throws IOException 2987 { 2988 return listNames(null); 2989 } 2990 2991 2992 2993 /** 2994 * Using the default system autodetect mechanism, obtain a 2995 * list of file information for the current working directory 2996 * or for just a single file. 2997 * <p> 2998 * This information is obtained through the LIST command. The contents of 2999 * the returned array is determined by the<code> FTPFileEntryParser </code> 3000 * used. 3001 * <p> 3002 * N.B. the LIST command does not generally return very precise timestamps. 3003 * For recent files, the response usually contains hours and minutes (not seconds). 3004 * For older files, the output may only contain a date. 3005 * If the server supports it, the MLSD command returns timestamps with a precision 3006 * of seconds, and may include milliseconds. See {@link #mlistDir()} 3007 * 3008 * @param pathname The file or directory to list. Since the server may 3009 * or may not expand glob expressions, using them here 3010 * is not recommended and may well cause this method to 3011 * fail. 3012 * Also, some servers treat a leading '-' as being an option. 3013 * To avoid this interpretation, use an absolute pathname 3014 * or prefix the pathname with ./ (unix style servers). 3015 * Some servers may support "--" as meaning end of options, 3016 * in which case "-- -xyz" should work. 3017 * 3018 * @return The list of file information contained in the given path in 3019 * the format determined by the autodetection mechanism 3020 * @throws FTPConnectionClosedException 3021 * If the FTP server prematurely closes the connection 3022 * as a result of the client being idle or some other 3023 * reason causing the server to send FTP reply code 421. 3024 * This exception may be caught either as an IOException 3025 * or independently as itself. 3026 * @throws IOException 3027 * If an I/O error occurs while either sending a 3028 * command to the server or receiving a reply 3029 * from the server. 3030 * @throws org.apache.commons.net.ftp.parser.ParserInitializationException 3031 * Thrown if the parserKey parameter cannot be 3032 * resolved by the selected parser factory. 3033 * In the DefaultFTPEntryParserFactory, this will 3034 * happen when parserKey is neither 3035 * the fully qualified class name of a class 3036 * implementing the interface 3037 * org.apache.commons.net.ftp.FTPFileEntryParser 3038 * nor a string containing one of the recognized keys 3039 * mapping to such a parser or if class loader 3040 * security issues prevent its being loaded. 3041 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory 3042 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory 3043 * @see org.apache.commons.net.ftp.FTPFileEntryParser 3044 */ 3045 public FTPFile[] listFiles(final String pathname) 3046 throws IOException 3047 { 3048 final FTPListParseEngine engine = initiateListParsing((String) null, pathname); 3049 return engine.getFiles(); 3050 3051 } 3052 3053 /** 3054 * Using the default system autodetect mechanism, obtain a 3055 * list of file information for the current working directory. 3056 * <p> 3057 * This information is obtained through the LIST command. The contents of 3058 * the returned array is determined by the<code> FTPFileEntryParser </code> 3059 * used. 3060 * <p> 3061 * N.B. the LIST command does not generally return very precise timestamps. 3062 * For recent files, the response usually contains hours and minutes (not seconds). 3063 * For older files, the output may only contain a date. 3064 * If the server supports it, the MLSD command returns timestamps with a precision 3065 * of seconds, and may include milliseconds. See {@link #mlistDir()} 3066 * 3067 * @return The list of file information contained in the current directory 3068 * in the format determined by the autodetection mechanism. 3069 * <p><b> 3070 * NOTE:</b> This array may contain null members if any of the 3071 * individual file listings failed to parse. The caller should 3072 * check each entry for null before referencing it. 3073 * @throws FTPConnectionClosedException 3074 * If the FTP server prematurely closes the connection 3075 * as a result of the client being idle or some other 3076 * reason causing the server to send FTP reply code 421. 3077 * This exception may be caught either as an IOException 3078 * or independently as itself. 3079 * @throws IOException 3080 * If an I/O error occurs while either sending a 3081 * command to the server or receiving a reply 3082 * from the server. 3083 * @throws org.apache.commons.net.ftp.parser.ParserInitializationException 3084 * Thrown if the parserKey parameter cannot be 3085 * resolved by the selected parser factory. 3086 * In the DefaultFTPEntryParserFactory, this will 3087 * happen when parserKey is neither 3088 * the fully qualified class name of a class 3089 * implementing the interface 3090 * org.apache.commons.net.ftp.FTPFileEntryParser 3091 * nor a string containing one of the recognized keys 3092 * mapping to such a parser or if class loader 3093 * security issues prevent its being loaded. 3094 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory 3095 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory 3096 * @see org.apache.commons.net.ftp.FTPFileEntryParser 3097 */ 3098 public FTPFile[] listFiles() 3099 throws IOException 3100 { 3101 return listFiles((String) null); 3102 } 3103 3104 /** 3105 * Version of {@link #listFiles(String)} which allows a filter to be provided. 3106 * For example: <code>listFiles("site", FTPFileFilters.DIRECTORY);</code> 3107 * @param pathname the initial path, may be null 3108 * @param filter the filter, non-null 3109 * @return the list of FTPFile entries. 3110 * @throws IOException on error 3111 * @since 2.2 3112 */ 3113 public FTPFile[] listFiles(final String pathname, final FTPFileFilter filter) 3114 throws IOException 3115 { 3116 final FTPListParseEngine engine = initiateListParsing((String) null, pathname); 3117 return engine.getFiles(filter); 3118 3119 } 3120 3121 /** 3122 * Using the default system autodetect mechanism, obtain a 3123 * list of directories contained in the current working directory. 3124 * <p> 3125 * This information is obtained through the LIST command. The contents of 3126 * the returned array is determined by the<code> FTPFileEntryParser </code> 3127 * used. 3128 * <p> 3129 * N.B. the LIST command does not generally return very precise timestamps. 3130 * For recent files, the response usually contains hours and minutes (not seconds). 3131 * For older files, the output may only contain a date. 3132 * If the server supports it, the MLSD command returns timestamps with a precision 3133 * of seconds, and may include milliseconds. See {@link #mlistDir()} 3134 * 3135 * @return The list of directories contained in the current directory 3136 * in the format determined by the autodetection mechanism. 3137 * 3138 * @throws FTPConnectionClosedException 3139 * If the FTP server prematurely closes the connection 3140 * as a result of the client being idle or some other 3141 * reason causing the server to send FTP reply code 421. 3142 * This exception may be caught either as an IOException 3143 * or independently as itself. 3144 * @throws IOException 3145 * If an I/O error occurs while either sending a 3146 * command to the server or receiving a reply 3147 * from the server. 3148 * @throws org.apache.commons.net.ftp.parser.ParserInitializationException 3149 * Thrown if the parserKey parameter cannot be 3150 * resolved by the selected parser factory. 3151 * In the DefaultFTPEntryParserFactory, this will 3152 * happen when parserKey is neither 3153 * the fully qualified class name of a class 3154 * implementing the interface 3155 * org.apache.commons.net.ftp.FTPFileEntryParser 3156 * nor a string containing one of the recognized keys 3157 * mapping to such a parser or if class loader 3158 * security issues prevent its being loaded. 3159 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory 3160 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory 3161 * @see org.apache.commons.net.ftp.FTPFileEntryParser 3162 * @since 3.0 3163 */ 3164 public FTPFile[] listDirectories() throws IOException { 3165 return listDirectories((String) null); 3166 } 3167 3168 /** 3169 * Using the default system autodetect mechanism, obtain a 3170 * list of directories contained in the specified directory. 3171 * <p> 3172 * This information is obtained through the LIST command. The contents of 3173 * the returned array is determined by the<code> FTPFileEntryParser </code> 3174 * used. 3175 * <p> 3176 * N.B. the LIST command does not generally return very precise timestamps. 3177 * For recent files, the response usually contains hours and minutes (not seconds). 3178 * For older files, the output may only contain a date. 3179 * If the server supports it, the MLSD command returns timestamps with a precision 3180 * of seconds, and may include milliseconds. See {@link #mlistDir()} 3181 * @param parent the starting directory 3182 * 3183 * @return The list of directories contained in the specified directory 3184 * in the format determined by the autodetection mechanism. 3185 * 3186 * @throws FTPConnectionClosedException 3187 * If the FTP server prematurely closes the connection 3188 * as a result of the client being idle or some other 3189 * reason causing the server to send FTP reply code 421. 3190 * This exception may be caught either as an IOException 3191 * or independently as itself. 3192 * @throws IOException 3193 * If an I/O error occurs while either sending a 3194 * command to the server or receiving a reply 3195 * from the server. 3196 * @throws org.apache.commons.net.ftp.parser.ParserInitializationException 3197 * Thrown if the parserKey parameter cannot be 3198 * resolved by the selected parser factory. 3199 * In the DefaultFTPEntryParserFactory, this will 3200 * happen when parserKey is neither 3201 * the fully qualified class name of a class 3202 * implementing the interface 3203 * org.apache.commons.net.ftp.FTPFileEntryParser 3204 * nor a string containing one of the recognized keys 3205 * mapping to such a parser or if class loader 3206 * security issues prevent its being loaded. 3207 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory 3208 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory 3209 * @see org.apache.commons.net.ftp.FTPFileEntryParser 3210 * @since 3.0 3211 */ 3212 public FTPFile[] listDirectories(final String parent) throws IOException { 3213 return listFiles(parent, FTPFileFilters.DIRECTORIES); 3214 } 3215 3216 /** 3217 * Using the default autodetect mechanism, initialize an FTPListParseEngine 3218 * object containing a raw file information for the current working 3219 * directory on the server 3220 * This information is obtained through the LIST command. This object 3221 * is then capable of being iterated to return a sequence of FTPFile 3222 * objects with information filled in by the 3223 * <code> FTPFileEntryParser </code> used. 3224 * <p> 3225 * This method differs from using the listFiles() methods in that 3226 * expensive FTPFile objects are not created until needed which may be 3227 * an advantage on large lists. 3228 * 3229 * @return A FTPListParseEngine object that holds the raw information and 3230 * is capable of providing parsed FTPFile objects, one for each file 3231 * containing information contained in the given path in the format 3232 * determined by the <code> parser </code> parameter. Null will be 3233 * returned if a data connection cannot be opened. If the current working 3234 * directory contains no files, an empty array will be the return. 3235 * 3236 * @throws FTPConnectionClosedException 3237 * If the FTP server prematurely closes the connection as a result 3238 * of the client being idle or some other reason causing the server 3239 * to send FTP reply code 421. This exception may be caught either 3240 * as an IOException or independently as itself. 3241 * @throws IOException 3242 * If an I/O error occurs while either sending a 3243 * command to the server or receiving a reply from the server. 3244 * @throws org.apache.commons.net.ftp.parser.ParserInitializationException 3245 * Thrown if the autodetect mechanism cannot 3246 * resolve the type of system we are connected with. 3247 * @see FTPListParseEngine 3248 */ 3249 public FTPListParseEngine initiateListParsing() 3250 throws IOException 3251 { 3252 return initiateListParsing((String) null); 3253 } 3254 3255 /** 3256 * Using the default autodetect mechanism, initialize an FTPListParseEngine 3257 * object containing a raw file information for the supplied directory. 3258 * This information is obtained through the LIST command. This object 3259 * is then capable of being iterated to return a sequence of FTPFile 3260 * objects with information filled in by the 3261 * <code> FTPFileEntryParser </code> used. 3262 * <p> 3263 * The server may or may not expand glob expressions. You should avoid 3264 * using glob expressions because the return format for glob listings 3265 * differs from server to server and will likely cause this method to fail. 3266 * <p> 3267 * This method differs from using the listFiles() methods in that 3268 * expensive FTPFile objects are not created until needed which may be 3269 * an advantage on large lists. 3270 * 3271 * <pre> 3272 * FTPClient f=FTPClient(); 3273 * f.connect(server); 3274 * f.login(username, password); 3275 * FTPListParseEngine engine = f.initiateListParsing(directory); 3276 * 3277 * while (engine.hasNext()) { 3278 * FTPFile[] files = engine.getNext(25); // "page size" you want 3279 * //do whatever you want with these files, display them, etc. 3280 * //expensive FTPFile objects not created until needed. 3281 * } 3282 * </pre> 3283 * @param pathname the starting directory 3284 * 3285 * @return A FTPListParseEngine object that holds the raw information and 3286 * is capable of providing parsed FTPFile objects, one for each file 3287 * containing information contained in the given path in the format 3288 * determined by the <code> parser </code> parameter. Null will be 3289 * returned if a data connection cannot be opened. If the current working 3290 * directory contains no files, an empty array will be the return. 3291 * 3292 * @throws FTPConnectionClosedException 3293 * If the FTP server prematurely closes the connection as a result 3294 * of the client being idle or some other reason causing the server 3295 * to send FTP reply code 421. This exception may be caught either 3296 * as an IOException or independently as itself. 3297 * @throws IOException 3298 * If an I/O error occurs while either sending a 3299 * command to the server or receiving a reply from the server. 3300 * @throws org.apache.commons.net.ftp.parser.ParserInitializationException 3301 * Thrown if the autodetect mechanism cannot 3302 * resolve the type of system we are connected with. 3303 * @see FTPListParseEngine 3304 */ 3305 public FTPListParseEngine initiateListParsing(final String pathname) 3306 throws IOException 3307 { 3308 return initiateListParsing((String) null, pathname); 3309 } 3310 3311 /** 3312 * Using the supplied parser key, initialize an FTPListParseEngine 3313 * object containing a raw file information for the supplied directory. 3314 * This information is obtained through the LIST command. This object 3315 * is then capable of being iterated to return a sequence of FTPFile 3316 * objects with information filled in by the 3317 * <code> FTPFileEntryParser </code> used. 3318 * <p> 3319 * The server may or may not expand glob expressions. You should avoid 3320 * using glob expressions because the return format for glob listings 3321 * differs from server to server and will likely cause this method to fail. 3322 * <p> 3323 * This method differs from using the listFiles() methods in that 3324 * expensive FTPFile objects are not created until needed which may be 3325 * an advantage on large lists. 3326 * 3327 * @param parserKey A string representing a designated code or fully-qualified 3328 * class name of an <code> FTPFileEntryParser </code> that should be 3329 * used to parse each server file listing. 3330 * May be {@code null}, in which case the code checks first 3331 * the system property {@link #FTP_SYSTEM_TYPE}, and if that is 3332 * not defined the SYST command is used to provide the value. 3333 * To allow for arbitrary system types, the return from the 3334 * SYST command is used to look up an alias for the type in the 3335 * {@link #SYSTEM_TYPE_PROPERTIES} properties file if it is available. 3336 * @param pathname the starting directory 3337 * 3338 * @return A FTPListParseEngine object that holds the raw information and 3339 * is capable of providing parsed FTPFile objects, one for each file 3340 * containing information contained in the given path in the format 3341 * determined by the <code> parser </code> parameter. Null will be 3342 * returned if a data connection cannot be opened. If the current working 3343 * directory contains no files, an empty array will be the return. 3344 * 3345 * @throws FTPConnectionClosedException 3346 * If the FTP server prematurely closes the connection as a result 3347 * of the client being idle or some other reason causing the server 3348 * to send FTP reply code 421. This exception may be caught either 3349 * as an IOException or independently as itself. 3350 * @throws IOException 3351 * If an I/O error occurs while either sending a 3352 * command to the server or receiving a reply from the server. 3353 * @throws org.apache.commons.net.ftp.parser.ParserInitializationException 3354 * Thrown if the parserKey parameter cannot be 3355 * resolved by the selected parser factory. 3356 * In the DefaultFTPEntryParserFactory, this will 3357 * happen when parserKey is neither 3358 * the fully qualified class name of a class 3359 * implementing the interface 3360 * org.apache.commons.net.ftp.FTPFileEntryParser 3361 * nor a string containing one of the recognized keys 3362 * mapping to such a parser or if class loader 3363 * security issues prevent its being loaded. 3364 * @see FTPListParseEngine 3365 */ 3366 public FTPListParseEngine initiateListParsing( 3367 final String parserKey, final String pathname) 3368 throws IOException 3369 { 3370 createParser(parserKey); // create and cache parser 3371 return initiateListParsing(entryParser, pathname); 3372 } 3373 3374 // package access for test purposes 3375 void createParser(final String parserKey) throws IOException { 3376 // We cache the value to avoid creation of a new object every 3377 // time a file listing is generated. 3378 // Note: we don't check against a null parserKey (NET-544) 3379 if(entryParser == null || (parserKey != null && ! entryParserKey.equals(parserKey))) { 3380 if (null != parserKey) { 3381 // if a parser key was supplied in the parameters, 3382 // use that to create the parser 3383 entryParser = 3384 parserFactory.createFileEntryParser(parserKey); 3385 entryParserKey = parserKey; 3386 3387 } else { 3388 // if no parserKey was supplied, check for a configuration 3389 // in the params, and if it has a non-empty system type, use that. 3390 if (null != configuration && configuration.getServerSystemKey().length() > 0) { 3391 entryParser = 3392 parserFactory.createFileEntryParser(configuration); 3393 entryParserKey = configuration.getServerSystemKey(); 3394 } else { 3395 // if a parserKey hasn't been supplied, and a configuration 3396 // hasn't been supplied, and the override property is not set 3397 // then autodetect by calling 3398 // the SYST command and use that to choose the parser. 3399 String systemType = System.getProperty(FTP_SYSTEM_TYPE); 3400 if (systemType == null) { 3401 systemType = getSystemType(); // cannot be null 3402 final Properties override = getOverrideProperties(); 3403 if (override != null) { 3404 final String newType = override.getProperty(systemType); 3405 if (newType != null) { 3406 systemType = newType; 3407 } 3408 } 3409 } 3410 if (null != configuration) { // system type must have been empty above 3411 entryParser = parserFactory.createFileEntryParser(new FTPClientConfig(systemType, configuration)); 3412 } else { 3413 entryParser = parserFactory.createFileEntryParser(systemType); 3414 } 3415 entryParserKey = systemType; 3416 } 3417 } 3418 } 3419 3420 3421 } 3422 3423 /** 3424 * private method through which all listFiles() and 3425 * initiateListParsing methods pass once a parser is determined. 3426 * 3427 * @throws FTPConnectionClosedException 3428 * If the FTP server prematurely closes the connection as a result 3429 * of the client being idle or some other reason causing the server 3430 * to send FTP reply code 421. This exception may be caught either 3431 * as an IOException or independently as itself. 3432 * @throws IOException 3433 * If an I/O error occurs while either sending a 3434 * command to the server or receiving a reply from the server. 3435 * @see FTPListParseEngine 3436 */ 3437 private FTPListParseEngine initiateListParsing( 3438 final FTPFileEntryParser parser, final String pathname) 3439 throws IOException 3440 { 3441 final Socket socket = _openDataConnection_(FTPCmd.LIST, getListArguments(pathname)); 3442 3443 final FTPListParseEngine engine = new FTPListParseEngine(parser, configuration); 3444 if (socket == null) 3445 { 3446 return engine; 3447 } 3448 3449 try { 3450 engine.readServerList(socket.getInputStream(), getControlEncoding()); 3451 } 3452 finally { 3453 Util.closeQuietly(socket); 3454 } 3455 3456 completePendingCommand(); 3457 return engine; 3458 } 3459 3460 /** 3461 * Initiate list parsing for MLSD listings in the current working directory. 3462 * 3463 * @return the engine 3464 * @throws IOException on error 3465 */ 3466 public FTPListParseEngine initiateMListParsing() throws IOException 3467 { 3468 return initiateMListParsing(null); 3469 } 3470 3471 /** 3472 * Initiate list parsing for MLSD listings. 3473 * 3474 * @param pathname the path from where to MLSD. 3475 * @return the engine. 3476 * @throws IOException on error 3477 */ 3478 public FTPListParseEngine initiateMListParsing(final String pathname) throws IOException 3479 { 3480 final Socket socket = _openDataConnection_(FTPCmd.MLSD, pathname); 3481 final FTPListParseEngine engine = new FTPListParseEngine(MLSxEntryParser.getInstance(), configuration); 3482 if (socket == null) 3483 { 3484 return engine; 3485 } 3486 3487 try { 3488 engine.readServerList(socket.getInputStream(), getControlEncoding()); 3489 } 3490 finally { 3491 Util.closeQuietly(socket); 3492 completePendingCommand(); 3493 } 3494 return engine; 3495 } 3496 3497 /** 3498 * @param pathname the initial pathname 3499 * @return the adjusted string with "-a" added if necessary 3500 * @since 2.0 3501 */ 3502 protected String getListArguments(final String pathname) { 3503 if (getListHiddenFiles()) 3504 { 3505 if (pathname != null) 3506 { 3507 final StringBuilder sb = new StringBuilder(pathname.length() + 3); 3508 sb.append("-a "); 3509 sb.append(pathname); 3510 return sb.toString(); 3511 } 3512 return "-a"; 3513 } 3514 3515 return pathname; 3516 } 3517 3518 3519 /** 3520 * Issue the FTP STAT command to the server. 3521 * 3522 * @return The status information returned by the server. 3523 * @throws FTPConnectionClosedException 3524 * If the FTP server prematurely closes the connection as a result 3525 * of the client being idle or some other reason causing the server 3526 * to send FTP reply code 421. This exception may be caught either 3527 * as an IOException or independently as itself. 3528 * @throws IOException If an I/O error occurs while either sending a 3529 * command to the server or receiving a reply from the server. 3530 */ 3531 public String getStatus() throws IOException 3532 { 3533 if (FTPReply.isPositiveCompletion(stat())) { 3534 return getReplyString(); 3535 } 3536 return null; 3537 } 3538 3539 3540 /** 3541 * Issue the FTP STAT command to the server for a given pathname. This 3542 * should produce a listing of the file or directory. 3543 * @param pathname the file name 3544 * 3545 * @return The status information returned by the server. 3546 * @throws FTPConnectionClosedException 3547 * If the FTP server prematurely closes the connection as a result 3548 * of the client being idle or some other reason causing the server 3549 * to send FTP reply code 421. This exception may be caught either 3550 * as an IOException or independently as itself. 3551 * @throws IOException If an I/O error occurs while either sending a 3552 * command to the server or receiving a reply from the server. 3553 */ 3554 public String getStatus(final String pathname) throws IOException 3555 { 3556 if (FTPReply.isPositiveCompletion(stat(pathname))) { 3557 return getReplyString(); 3558 } 3559 return null; 3560 } 3561 3562 3563 /** 3564 * Issue the FTP SIZE command to the server for a given pathname. 3565 * This should produce the size of the file. 3566 * 3567 * @param pathname the file name 3568 * 3569 * @return The size information returned by the server; {@code null} if there was an error 3570 * @throws FTPConnectionClosedException 3571 * If the FTP server prematurely closes the connection as a result 3572 * of the client being idle or some other reason causing the server 3573 * to send FTP reply code 421. This exception may be caught either 3574 * as an IOException or independently as itself. 3575 * @throws IOException If an I/O error occurs while either sending a 3576 * command to the server or receiving a reply from the server. 3577 * @since 3.7 3578 */ 3579 public String getSize(final String pathname) throws IOException 3580 { 3581 if (FTPReply.isPositiveCompletion(size(pathname))) { 3582 return getReplyStrings()[0].substring(4); // skip the return code (e.g. 213) and the space 3583 } 3584 return null; 3585 } 3586 3587 3588 /** 3589 * Issue the FTP MDTM command (not supported by all servers) to retrieve the last 3590 * modification time of a file. The modification string should be in the 3591 * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in 3592 * GMT, but not all FTP servers honour this. 3593 * 3594 * @param pathname The file path to query. 3595 * @return A string representing the last file modification time in <code>YYYYMMDDhhmmss</code> format. 3596 * @throws IOException if an I/O error occurs. 3597 * @since 2.0 3598 */ 3599 public String getModificationTime(final String pathname) throws IOException { 3600 if (FTPReply.isPositiveCompletion(mdtm(pathname))) { 3601 return getReplyStrings()[0].substring(4); // skip the return code (e.g. 213) and the space 3602 } 3603 return null; 3604 } 3605 3606 3607 /** 3608 * Issue the FTP MDTM command (not supported by all servers) to retrieve the last 3609 * modification time of a file. The modification string should be in the 3610 * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in 3611 * GMT, but not all FTP servers honour this. 3612 * 3613 * @param pathname The file path to query. 3614 * @return A FTPFile representing the last file modification time, may be {@code null}. 3615 * The FTPFile timestamp will be null if a parse error occurs. 3616 * @throws IOException if an I/O error occurs. 3617 * @since 3.4 3618 */ 3619 public FTPFile mdtmFile(final String pathname) throws IOException { 3620 if (FTPReply.isPositiveCompletion(mdtm(pathname))) { 3621 final String reply = getReplyStrings()[0].substring(4); // skip the return code (e.g. 213) and the space 3622 final FTPFile file = new FTPFile(); 3623 file.setName(pathname); 3624 file.setRawListing(reply); 3625 file.setTimestamp(MLSxEntryParser.parseGMTdateTime(reply)); 3626 return file; 3627 } 3628 return null; 3629 } 3630 3631 3632 /** 3633 * Issue the FTP MFMT command (not supported by all servers) which sets the last 3634 * modified time of a file. 3635 * 3636 * The timestamp should be in the form <code>YYYYMMDDhhmmss</code>. It should also 3637 * be in GMT, but not all servers honour this. 3638 * 3639 * An FTP server would indicate its support of this feature by including "MFMT" 3640 * in its response to the FEAT command, which may be retrieved by FTPClient.features() 3641 * 3642 * @param pathname The file path for which last modified time is to be changed. 3643 * @param timeval The timestamp to set to, in <code>YYYYMMDDhhmmss</code> format. 3644 * @return true if successfully set, false if not 3645 * @throws IOException if an I/O error occurs. 3646 * @since 2.2 3647 * @see <a href="http://tools.ietf.org/html/draft-somers-ftp-mfxx-04">http://tools.ietf.org/html/draft-somers-ftp-mfxx-04</a> 3648 */ 3649 public boolean setModificationTime(final String pathname, final String timeval) throws IOException { 3650 return (FTPReply.isPositiveCompletion(mfmt(pathname, timeval))); 3651 } 3652 3653 3654 /** 3655 * Set the internal buffer size for buffered data streams. 3656 * 3657 * @param bufSize The size of the buffer. Use a non-positive value to use the default. 3658 */ 3659 public void setBufferSize(final int bufSize) { 3660 bufferSize = bufSize; 3661 } 3662 3663 /** 3664 * Retrieve the current internal buffer size for buffered data streams. 3665 * @return The current buffer size. 3666 */ 3667 public int getBufferSize() { 3668 return bufferSize; 3669 } 3670 3671 /** 3672 * Sets the value to be used for the data socket SO_SNDBUF option. 3673 * If the value is positive, the option will be set when the data socket has been created. 3674 * 3675 * @param bufSize The size of the buffer, zero or negative means the value is ignored. 3676 * @since 3.3 3677 */ 3678 public void setSendDataSocketBufferSize(final int bufSize) { 3679 sendDataSocketBufferSize = bufSize; 3680 } 3681 3682 /** 3683 * Retrieve the value to be used for the data socket SO_SNDBUF option. 3684 * @return The current buffer size. 3685 * @since 3.3 3686 */ 3687 public int getSendDataSocketBufferSize() { 3688 return sendDataSocketBufferSize; 3689 } 3690 3691 /** 3692 * Sets the value to be used for the data socket SO_RCVBUF option. 3693 * If the value is positive, the option will be set when the data socket has been created. 3694 * 3695 * @param bufSize The size of the buffer, zero or negative means the value is ignored. 3696 * @since 3.3 3697 */ 3698 public void setReceieveDataSocketBufferSize(final int bufSize) { 3699 receiveDataSocketBufferSize = bufSize; 3700 } 3701 3702 /** 3703 * Retrieve the value to be used for the data socket SO_RCVBUF option. 3704 * @return The current buffer size. 3705 * @since 3.3 3706 */ 3707 public int getReceiveDataSocketBufferSize() { 3708 return receiveDataSocketBufferSize; 3709 } 3710 3711 /** 3712 * Implementation of the {@link Configurable Configurable} interface. 3713 * In the case of this class, configuring merely makes the config object available for the 3714 * factory methods that construct parsers. 3715 * @param config {@link FTPClientConfig FTPClientConfig} object used to 3716 * provide non-standard configurations to the parser. 3717 * @since 1.4 3718 */ 3719 @Override 3720 public void configure(final FTPClientConfig config) { 3721 this.configuration = config; 3722 } 3723 3724 /** 3725 * You can set this to true if you would like to get hidden files when {@link #listFiles} too. 3726 * A <code>LIST -a</code> will be issued to the ftp server. 3727 * It depends on your ftp server if you need to call this method, also dont expect to get rid 3728 * of hidden files if you call this method with "false". 3729 * 3730 * @param listHiddenFiles true if hidden files should be listed 3731 * @since 2.0 3732 */ 3733 public void setListHiddenFiles(final boolean listHiddenFiles) { 3734 this.listHiddenFiles = listHiddenFiles; 3735 } 3736 3737 /** 3738 * @see #setListHiddenFiles(boolean) 3739 * @return the current state 3740 * @since 2.0 3741 */ 3742 public boolean getListHiddenFiles() { 3743 return this.listHiddenFiles; 3744 } 3745 3746 /** 3747 * Whether should attempt to use EPSV with IPv4. 3748 * Default (if not set) is <code>false</code> 3749 * @return true if should attempt EPSV 3750 * @since 2.2 3751 */ 3752 public boolean isUseEPSVwithIPv4() { 3753 return useEPSVwithIPv4; 3754 } 3755 3756 3757 /** 3758 * Set whether to use EPSV with IPv4. 3759 * Might be worth enabling in some circumstances. 3760 * 3761 * For example, when using IPv4 with NAT it 3762 * may work with some rare configurations. 3763 * E.g. if FTP server has a static PASV address (external network) 3764 * and the client is coming from another internal network. 3765 * In that case the data connection after PASV command would fail, 3766 * while EPSV would make the client succeed by taking just the port. 3767 * 3768 * @param selected value to set. 3769 * @since 2.2 3770 */ 3771 public void setUseEPSVwithIPv4(final boolean selected) { 3772 this.useEPSVwithIPv4 = selected; 3773 } 3774 3775 /** 3776 * Set the listener to be used when performing store/retrieve operations. 3777 * The default value (if not set) is {@code null}. 3778 * 3779 * @param listener to be used, may be {@code null} to disable 3780 * @since 3.0 3781 */ 3782 public void setCopyStreamListener(final CopyStreamListener listener){ 3783 copyStreamListener = listener; 3784 } 3785 3786 /** 3787 * Obtain the currently active listener. 3788 * 3789 * @return the listener, may be {@code null} 3790 * @since 3.0 3791 */ 3792 public CopyStreamListener getCopyStreamListener(){ 3793 return copyStreamListener; 3794 } 3795 3796 /** 3797 * Set the time to wait between sending control connection keepalive messages 3798 * when processing file upload or download. 3799 * <p> 3800 * See the class Javadoc section "Control channel keep-alive feature:" 3801 * 3802 * @param controlIdle the wait (in secs) between keepalive messages. Zero (or less) disables. 3803 * @since 3.0 3804 * @see #setControlKeepAliveReplyTimeout(int) 3805 */ 3806 public void setControlKeepAliveTimeout(final long controlIdle){ 3807 controlKeepAliveTimeout = controlIdle * 1000; 3808 } 3809 3810 /** 3811 * Get the time to wait between sending control connection keepalive messages 3812 * when processing file upload or download. 3813 * <p> 3814 * See the class Javadoc section "Control channel keep-alive feature:" 3815 * 3816 * @return the number of seconds between keepalive messages. 3817 * @since 3.0 3818 */ 3819 public long getControlKeepAliveTimeout() { 3820 return controlKeepAliveTimeout / 1000; 3821 } 3822 3823 /** 3824 * Get the CSL debug array. 3825 * <p> 3826 * <b>For debug use only</b> 3827 * <p> 3828 * Currently contains: 3829 * <ul> 3830 * <li>successfully acked NOOPs at end of transfer</li> 3831 * <li>unanswered NOOPs at end of transfer</li> 3832 * <li>unanswered NOOPs after fetching additional replies</li> 3833 * <li>Number of IOErrors ignored</li> 3834 * </ul> 3835 * @return the debug array 3836 * @deprecated 3.7 For testing only; may be dropped or changed at any time 3837 */ 3838 @Deprecated // only for use in testing 3839 public int[] getCslDebug() { 3840 return cslDebug; 3841 } 3842 /** 3843 * Set how long to wait for control keep-alive message replies. 3844 * 3845 * @param timeout number of milliseconds to wait (defaults to 1000) 3846 * @since 3.0 3847 * @see #setControlKeepAliveTimeout(long) 3848 */ 3849 public void setControlKeepAliveReplyTimeout(final int timeout) { 3850 controlKeepAliveReplyTimeout = timeout; 3851 } 3852 3853 /** 3854 * Get how long to wait for control keep-alive message replies. 3855 * @return wait time in msec 3856 * @since 3.0 3857 */ 3858 public int getControlKeepAliveReplyTimeout() { 3859 return controlKeepAliveReplyTimeout; 3860 } 3861 3862 /** 3863 * Enable or disable passive mode NAT workaround. 3864 * If enabled, a site-local PASV mode reply address will be replaced with the 3865 * remote host address to which the PASV mode request was sent 3866 * (unless that is also a site local address). 3867 * This gets around the problem that some NAT boxes may change the 3868 * reply. 3869 * 3870 * The default is true, i.e. site-local replies are replaced. 3871 * @param enabled true to enable replacing internal IP's in passive 3872 * mode. 3873 * @deprecated (3.6) use {@link #setPassiveNatWorkaroundStrategy(HostnameResolver)} instead 3874 */ 3875 @Deprecated 3876 public void setPassiveNatWorkaround(final boolean enabled) { 3877 if (enabled) { 3878 this.passiveNatWorkaroundStrategy = new NatServerResolverImpl(this); 3879 } else { 3880 this.passiveNatWorkaroundStrategy = null; 3881 } 3882 } 3883 3884 /** 3885 * Set the workaround strategy to replace the PASV mode reply addresses. 3886 * This gets around the problem that some NAT boxes may change the reply. 3887 * 3888 * The default implementation is {@code NatServerResolverImpl}, i.e. site-local 3889 * replies are replaced. 3890 * @param resolver strategy to replace internal IP's in passive mode 3891 * or null to disable the workaround (i.e. use PASV mode reply address.) 3892 * @since 3.6 3893 */ 3894 public void setPassiveNatWorkaroundStrategy(final HostnameResolver resolver) { 3895 this.passiveNatWorkaroundStrategy = resolver; 3896 } 3897 3898 /** 3899 * Strategy interface for updating host names received from FTP server 3900 * for passive NAT workaround. 3901 * 3902 * @since 3.6 3903 */ 3904 public interface HostnameResolver { 3905 String resolve(String hostname) throws UnknownHostException; 3906 } 3907 3908 /** 3909 * Default strategy for passive NAT workaround (site-local 3910 * replies are replaced.) 3911 * @since 3.6 3912 */ 3913 public static class NatServerResolverImpl implements HostnameResolver { 3914 private final FTPClient client; 3915 3916 public NatServerResolverImpl(final FTPClient client) { 3917 this.client = client; 3918 } 3919 3920 @Override 3921 public String resolve(final String hostname) throws UnknownHostException { 3922 String newHostname = hostname; 3923 final InetAddress host = InetAddress.getByName(newHostname); 3924 // reply is a local address, but target is not - assume NAT box changed the PASV reply 3925 if (host.isSiteLocalAddress()) { 3926 final InetAddress remote = this.client.getRemoteAddress(); 3927 if (!remote.isSiteLocalAddress()){ 3928 newHostname = remote.getHostAddress(); 3929 } 3930 } 3931 return newHostname; 3932 } 3933 } 3934 3935 private OutputStream getBufferedOutputStream(final OutputStream outputStream) { 3936 if (bufferSize > 0) { 3937 return new BufferedOutputStream(outputStream, bufferSize); 3938 } 3939 return new BufferedOutputStream(outputStream); 3940 } 3941 3942 private InputStream getBufferedInputStream(final InputStream inputStream) { 3943 if (bufferSize > 0) { 3944 return new BufferedInputStream(inputStream, bufferSize); 3945 } 3946 return new BufferedInputStream(inputStream); 3947 } 3948 3949 // @since 3.0 3950 private static class CSL implements CopyStreamListener { 3951 3952 private final FTPClient parent; 3953 private final long idle; 3954 private final int currentSoTimeout; 3955 3956 private long time = System.currentTimeMillis(); 3957 private int notAcked; 3958 private int acksAcked; 3959 private int ioErrors; 3960 3961 CSL(final FTPClient parent, final long idleTime, final int maxWait) throws SocketException { 3962 this.idle = idleTime; 3963 this.parent = parent; 3964 this.currentSoTimeout = parent.getSoTimeout(); 3965 parent.setSoTimeout(maxWait); 3966 } 3967 3968 @Override 3969 public void bytesTransferred(final CopyStreamEvent event) { 3970 bytesTransferred(event.getTotalBytesTransferred(), event.getBytesTransferred(), event.getStreamSize()); 3971 } 3972 3973 @Override 3974 public void bytesTransferred(final long totalBytesTransferred, 3975 final int bytesTransferred, final long streamSize) { 3976 final long now = System.currentTimeMillis(); 3977 if (now - time > idle) { 3978 try { 3979 parent.__noop(); 3980 acksAcked++; 3981 } catch (final SocketTimeoutException e) { 3982 notAcked++; 3983 } catch (final IOException e) { 3984 ioErrors++; 3985 // Ignored 3986 } 3987 time = now; 3988 } 3989 } 3990 3991 int[] cleanUp() throws IOException { 3992 final int remain = notAcked; 3993 try { 3994 while(notAcked > 0) { 3995 parent.getReply(); // we do want to see these 3996 notAcked--; // only decrement if actually received 3997 } 3998 } catch (final SocketTimeoutException e) { // NET-584 3999 // ignored 4000 } finally { 4001 parent.setSoTimeout(currentSoTimeout); 4002 } 4003 return new int [] {acksAcked, remain, notAcked, ioErrors}; // debug counts 4004 } 4005 4006 } 4007 4008 /** 4009 * Merge two copystream listeners, either or both of which may be null. 4010 * 4011 * @param local the listener used by this class, may be null 4012 * @return a merged listener or a single listener or null 4013 * @since 3.0 4014 */ 4015 private CopyStreamListener mergeListeners(final CopyStreamListener local) { 4016 if (local == null) { 4017 return copyStreamListener; 4018 } 4019 if (copyStreamListener == null) { 4020 return local; 4021 } 4022 // Both are non-null 4023 final CopyStreamAdapter merged = new CopyStreamAdapter(); 4024 merged.addCopyStreamListener(local); 4025 merged.addCopyStreamListener(copyStreamListener); 4026 return merged; 4027 } 4028 4029 /** 4030 * Enables or disables automatic server encoding detection (only UTF-8 supported). 4031 * <p> 4032 * Does not affect existing connections; must be invoked before a connection is established. 4033 * 4034 * @param autodetect If true, automatic server encoding detection will be enabled. 4035 */ 4036 public void setAutodetectUTF8(final boolean autodetect) 4037 { 4038 autodetectEncoding = autodetect; 4039 } 4040 4041 /** 4042 * Tells if automatic server encoding detection is enabled or disabled. 4043 * @return true, if automatic server encoding detection is enabled. 4044 */ 4045 public boolean getAutodetectUTF8() 4046 { 4047 return autodetectEncoding; 4048 } 4049 4050 // Method for use by unit test code only 4051 FTPFileEntryParser getEntryParser() { 4052 return entryParser; 4053 } 4054 4055 // DEPRECATED METHODS - for API compatibility only - DO NOT USE 4056 4057 /** 4058 * @return the name 4059 * @throws IOException on error 4060 * @deprecated use {@link #getSystemType()} instead 4061 */ 4062 @Deprecated 4063 public String getSystemName() throws IOException 4064 { 4065 if (systemName == null && FTPReply.isPositiveCompletion(syst())) { 4066 systemName = _replyLines.get(_replyLines.size() - 1).substring(4); 4067 } 4068 return systemName; 4069 } 4070} 4071 4072/* Emacs configuration 4073 * Local variables: ** 4074 * mode: java ** 4075 * c-basic-offset: 4 ** 4076 * indent-tabs-mode: nil ** 4077 * End: ** 4078 */ 4079/* kate: indent-width 4; replace-tabs on; */