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