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