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