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