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