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