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