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