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