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