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