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