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