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