    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
    018package org.apache.commons.net.ftp;
    019
    020import java.io.BufferedReader;
    021import java.io.BufferedWriter;
    022import java.io.IOException;
    023import java.io.InputStreamReader;
    024import java.io.OutputStreamWriter;
    025import java.io.Reader;
    026import java.net.Inet4Address;
    027import java.net.Inet6Address;
    028import java.net.InetAddress;
    029import java.net.SocketException;
    030import java.net.SocketTimeoutException;
    031import java.util.ArrayList;
    032
    033import org.apache.commons.net.MalformedServerReplyException;
    034import org.apache.commons.net.ProtocolCommandSupport;
    035import org.apache.commons.net.SocketClient;
    036import org.apache.commons.net.io.CRLFLineReader;
    037import org.apache.commons.net.util.NetConstants;
    038
    039/**
    040 * FTP provides the basic the functionality necessary to implement your own FTP client. It extends org.apache.commons.net.SocketClient since extending
    041 * TelnetClient was causing unwanted behavior (like connections that did not time out properly).
    042 * <p>
    043 * To derive the full benefits of the FTP class requires some knowledge of the FTP protocol defined in RFC 959. However, there is no reason why you should have
    044 * to use the FTP class. The {@link org.apache.commons.net.ftp.FTPClient} class, derived from FTP, implements all the functionality required of an FTP client.
    045 * The FTP class is made public to provide access to various FTP constants and to make it easier for adventurous programmers (or those with special needs) to
    046 * interact with the FTP protocol and implement their own clients. A set of methods with names corresponding to the FTP command names are provided to facilitate
    047 * this interaction.
    048 * <p>
    049 * You should keep in mind that the FTP server may choose to prematurely close a connection if the client has been idle for longer than a given time period
    050 * (usually 900 seconds). The FTP class will detect a premature FTP server connection closing when it receives a
    051 * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } response to a command. When that occurs, the FTP class
    052 * method encountering that reply will throw an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} . <code>FTPConectionClosedException</code> is a
    053 * subclass of <code> IOException </code> and therefore need not be caught separately, but if you are going to catch it separately, its catch block must appear
    054 * before the more general <code> IOException </code> catch block. When you encounter an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} , you
    055 * must disconnect the connection with {@link #disconnect disconnect() } to properly clean up the system resources used by FTP. Before disconnecting, you may
    056 * check the last reply code and text with {@link #getReplyCode getReplyCode }, {@link #getReplyString getReplyString }, and {@link #getReplyStrings
    057 * getReplyStrings}. You may avoid server disconnections while the client is idle by periodicaly sending NOOP commands to the server.
    058 * <p>
    059 * Rather than list it separately for each method, we mention here that every method communicating with the server and throwing an IOException can also throw a
    060 * {@link org.apache.commons.net.MalformedServerReplyException} , which is a subclass of IOException. A MalformedServerReplyException will be thrown when the
    061 * reply received from the server deviates enough from the protocol specification that it cannot be interpreted in a useful manner despite attempts to be as
    062 * lenient as possible.
    063 *
    064 * @see FTPClient
    065 * @see FTPConnectionClosedException
    066 * @see org.apache.commons.net.MalformedServerReplyException
    067 */
    068
    069public class FTP extends SocketClient {
    070    /** The default FTP data port (20). */
    071    public static final int DEFAULT_DATA_PORT = 20;
    072    /** The default FTP control port (21). */
    073    public static final int DEFAULT_PORT = 21;
    074
    075    /**
    076     * A constant used to indicate the file(s) being transferred should be treated as ASCII. This is the default file type. All constants ending in
    077     * <code>FILE_TYPE</code> are used to indicate file types.
    078     */
    079    public static final int ASCII_FILE_TYPE = 0;
    080
    081    /**
    082     * A constant used to indicate the file(s) being transferred should be treated as EBCDIC. Note however that there are several different EBCDIC formats. All
    083     * constants ending in <code>FILE_TYPE</code> are used to indicate file types.
    084     */
    085    public static final int EBCDIC_FILE_TYPE = 1;
    086
    087    /**
    088     * A constant used to indicate the file(s) being transferred should be treated as a binary image, i.e., no translations should be performed. All constants
    089     * ending in <code>FILE_TYPE</code> are used to indicate file types.
    090     */
    091    public static final int BINARY_FILE_TYPE = 2;
    092
    093    /**
    094     * A constant used to indicate the file(s) being transferred should be treated as a local type. All constants ending in <code>FILE_TYPE</code> are used to
    095     * indicate file types.
    096     */
    097    public static final int LOCAL_FILE_TYPE = 3;
    098
    099    /**
    100     * A constant used for text files to indicate a non-print text format. This is the default format. All constants ending in <code>TEXT_FORMAT</code> are used
    101     * to indicate text formatting for text transfers (both ASCII and EBCDIC).
    102     */
    103    public static final int NON_PRINT_TEXT_FORMAT = 4;
    104
    105    /**
    106     * A constant used to indicate a text file contains format vertical format control characters. All constants ending in <code>TEXT_FORMAT</code> are used to
    107     * indicate text formatting for text transfers (both ASCII and EBCDIC).
    108     */
    109    public static final int TELNET_TEXT_FORMAT = 5;
    110
    111    /**
    112     * A constant used to indicate a text file contains ASA vertical format control characters. All constants ending in <code>TEXT_FORMAT</code> are used to
    113     * indicate text formatting for text transfers (both ASCII and EBCDIC).
    114     */
    115    public static final int CARRIAGE_CONTROL_TEXT_FORMAT = 6;
    116
    117    /**
    118     * A constant used to indicate a file is to be treated as a continuous sequence of bytes. This is the default structure. All constants ending in
    119     * <code>_STRUCTURE</code> are used to indicate file structure for file transfers.
    120     */
    121    public static final int FILE_STRUCTURE = 7;
    122
    123    /**
    124     * A constant used to indicate a file is to be treated as a sequence of records. All constants ending in <code>_STRUCTURE</code> are used to indicate file
    125     * structure for file transfers.
    126     */
    127    public static final int RECORD_STRUCTURE = 8;
    128
    129    /**
    130     * A constant used to indicate a file is to be treated as a set of independent indexed pages. All constants ending in <code>_STRUCTURE</code> are used to
    131     * indicate file structure for file transfers.
    132     */
    133    public static final int PAGE_STRUCTURE = 9;
    134
    135    /**
    136     * A constant used to indicate a file is to be transferred as a stream of bytes. This is the default transfer mode. All constants ending in
    137     * <code>TRANSFER_MODE</code> are used to indicate file transfer modes.
    138     */
    139    public static final int STREAM_TRANSFER_MODE = 10;
    140
    141    /**
    142     * A constant used to indicate a file is to be transferred as a series of blocks. All constants ending in <code>TRANSFER_MODE</code> are used to indicate
    143     * file transfer modes.
    144     */
    145    public static final int BLOCK_TRANSFER_MODE = 11;
    146
    147    /**
    148     * A constant used to indicate a file is to be transferred as FTP compressed data. All constants ending in <code>TRANSFER_MODE</code> are used to indicate
    149     * file transfer modes.
    150     */
    151    public static final int COMPRESSED_TRANSFER_MODE = 12;
    152
    153    // We have to ensure that the protocol communication is in ASCII
    154    // but we use ISO-8859-1 just in case 8-bit characters cross
    155    // the wire.
    156    /**
    157     * The default character encoding used for communicating over an FTP control connection. The default encoding is an ASCII-compatible encoding. Some FTP
    158     * servers expect other encodings. You can change the encoding used by an FTP instance with {@link #setControlEncoding setControlEncoding}.
    159     */
    160    public static final String DEFAULT_CONTROL_ENCODING = "ISO-8859-1";
    161
    162    /** Length of the FTP reply code (3 alphanumerics) */
    163    public static final int REPLY_CODE_LEN = 3;
    164
    165    private static final String modes = "AEILNTCFRPSBC";
    166    protected int _replyCode;
    167    protected ArrayList<String> _replyLines;
    168    protected boolean _newReplyString;
    169    protected String _replyString;
    170    protected String _controlEncoding;
    171
    172    /**
    173     * A ProtocolCommandSupport object used to manage the registering of ProtocolCommandListeners and the firing of ProtocolCommandEvents.
    174     */
    175    protected ProtocolCommandSupport _commandSupport_;
    176
    177    /**
    178     * This is used to signal whether a block of multiline responses beginning with xxx must be terminated by the same numeric code xxx See section 4.2 of RFC
    179     * 959 for details.
    180     */
    181    protected boolean strictMultilineParsing;
    182
    183    /**
    184     * If this is true, then non-multiline replies must have the format: 3 digit code <space> <text> If false, then the 3 digit code does not have to be
    185     * followed by space See section 4.2 of RFC 959 for details.
    186     */
    187    private boolean strictReplyParsing = true;
    188
    189    /**
    190     * Wraps SocketClient._input_ to facilitate the reading of text from the FTP control connection. Do not access the control connection via
    191     * SocketClient._input_. This member starts with a null value, is initialized in {@link #_connectAction_}, and set to null in {@link #disconnect}.
    192     */
    193    protected BufferedReader _controlInput_;
    194
    195    /**
    196     * Wraps SocketClient._output_ to facilitate the writing of text to the FTP control connection. Do not access the control connection via
    197     * SocketClient._output_. This member starts with a null value, is initialized in {@link #_connectAction_}, and set to null in {@link #disconnect}.
    198     */
    199    protected BufferedWriter _controlOutput_;
    200
    201    /**
    202     * The default FTP constructor. Sets the default port to <code>DEFAULT_PORT</code> and initializes internal data structures for saving FTP reply
    203     * information.
    204     */
    205    public FTP() {
    206        setDefaultPort(DEFAULT_PORT);
    207        _replyLines = new ArrayList<>();
    208        _newReplyString = false;
    209        _replyString = null;
    210        _controlEncoding = DEFAULT_CONTROL_ENCODING;
    211        _commandSupport_ = new ProtocolCommandSupport(this);
    212    }
    213
    214    /**
    215     * Get the reply, but don't pass it to command listeners. Used for keep-alive processing only.
    216     *
    217     * @since 3.0
    218     * @throws IOException on error
    219     */
    220    protected void __getReplyNoReport() throws IOException {
    221        getReply(false);
    222    }
    223
    224    /**
    225     * Send a noop and get the reply without reporting to the command listener. Intended for use with keep-alive.
    226     *
    227     * @throws IOException on error
    228     * @since 3.0
    229     */
    230    protected void __noop() throws IOException {
    231        final String msg = buildMessage(FTPCmd.NOOP.getCommand(), null);
    232        send(msg);
    233        __getReplyNoReport(); // This may timeout
    234    }
    235
    236    /**
    237     * Initiates control connections and gets initial reply. Initializes {@link #_controlInput_} and {@link #_controlOutput_}.
    238     */
    239    @Override
    240    protected void _connectAction_() throws IOException {
    241        _connectAction_(null);
    242    }
    243
    244    /**
    245     * Initiates control connections and gets initial reply. Initializes {@link #_controlInput_} and {@link #_controlOutput_}.
    246     *
    247     * @param socketIsReader the reader to reuse (if non-null)
    248     * @throws IOException on error
    249     * @since 3.4
    250     */
    251    protected void _connectAction_(final Reader socketIsReader) throws IOException {
    252        super._connectAction_(); // sets up _input_ and _output_
    253        if (socketIsReader == null) {
    254            _controlInput_ = new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding()));
    255        } else {
    256            _controlInput_ = new CRLFLineReader(socketIsReader);
    257        }
    258        _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding()));
    259        if (connectTimeout > 0) { // NET-385
    260            final int original = _socket_.getSoTimeout();
    261            _socket_.setSoTimeout(connectTimeout);
    262            try {
    263                getReply();
    264                // If we received code 120, we have to fetch completion reply.
    265                if (FTPReply.isPositivePreliminary(_replyCode)) {
    266                    getReply();
    267                }
    268            } catch (final SocketTimeoutException e) {
    269                final IOException ioe = new IOException("Timed out waiting for initial connect reply");
    270                ioe.initCause(e);
    271                throw ioe;
    272            } finally {
    273                _socket_.setSoTimeout(original);
    274            }
    275        } else {
    276            getReply();
    277            // If we received code 120, we have to fetch completion reply.
    278            if (FTPReply.isPositivePreliminary(_replyCode)) {
    279                getReply();
    280            }
    281        }
    282    }
    283
    284    /**
    285     * A convenience method to send the FTP ABOR command to the server, receive the reply, and return the reply code.
    286     *
    287     * @return The reply code received from the server.
    288     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    289     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    290     *                                      independently as itself.
    291     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    292     */
    293    public int abor() throws IOException {
    294        return sendCommand(FTPCmd.ABOR);
    295    }
    296
    297    /**
    298     * A convenience method to send the FTP ACCT command to the server, receive the reply, and return the reply code.
    299     *
    300     * @param account The account name to access.
    301     * @return The reply code received from the server.
    302     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    303     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    304     *                                      independently as itself.
    305     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    306     */
    307    public int acct(final String account) throws IOException {
    308        return sendCommand(FTPCmd.ACCT, account);
    309    }
    310
    311    /**
    312     * A convenience method to send the FTP ALLO command to the server, receive the reply, and return the reply code.
    313     *
    314     * @param bytes The number of bytes to allocate.
    315     * @return The reply code received from the server.
    316     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    317     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    318     *                                      independently as itself.
    319     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    320     */
    321    public int allo(final int bytes) throws IOException {
    322        return sendCommand(FTPCmd.ALLO, Integer.toString(bytes));
    323    }
    324
    325    /**
    326     * A convenience method to send the FTP ALLO command to the server, receive the reply, and return the reply code.
    327     *
    328     * @param bytes      The number of bytes to allocate.
    329     * @param recordSize The size of a record.
    330     * @return The reply code received from the server.
    331     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    332     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    333     *                                      independently as itself.
    334     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    335     */
    336    public int allo(final int bytes, final int recordSize) throws IOException {
    337        return sendCommand(FTPCmd.ALLO, Integer.toString(bytes) + " R " + Integer.toString(recordSize));
    338    }
    339
    340    /**
    341     * A convenience method to send the FTP ALLO command to the server, receive the reply, and return the reply code.
    342     *
    343     * @param bytes The number of bytes to allocate.
    344     * @return The reply code received from the server.
    345     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    346     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    347     *                                      independently as itself.
    348     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    349     */
    350    public int allo(final long bytes) throws IOException {
    351        return sendCommand(FTPCmd.ALLO, Long.toString(bytes));
    352    }
    353
    354    /**
    355     * A convenience method to send the FTP ALLO command to the server, receive the reply, and return the reply code.
    356     *
    357     * @param bytes      The number of bytes to allocate.
    358     * @param recordSize The size of a record.
    359     * @return The reply code received from the server.
    360     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    361     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    362     *                                      independently as itself.
    363     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    364     */
    365    public int allo(final long bytes, final int recordSize) throws IOException {
    366        return sendCommand(FTPCmd.ALLO, Long.toString(bytes) + " R " + Integer.toString(recordSize));
    367    }
    368
    369    /**
    370     * A convenience method to send the FTP APPE command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    371     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    372     * for you.
    373     *
    374     * @param pathname The pathname to use for the file when stored at the remote end of the transfer.
    375     * @return The reply code received from the server.
    376     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    377     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    378     *                                      independently as itself.
    379     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    380     */
    381    public int appe(final String pathname) throws IOException {
    382        return sendCommand(FTPCmd.APPE, pathname);
    383    }
    384
    385    private String buildMessage(final String command, final String args) {
    386        final StringBuilder __commandBuffer = new StringBuilder();
    387
    388        __commandBuffer.append(command);
    389
    390        if (args != null) {
    391            __commandBuffer.append(' ');
    392            __commandBuffer.append(args);
    393        }
    394        __commandBuffer.append(SocketClient.NETASCII_EOL);
    395        return __commandBuffer.toString();
    396    }
    397
    398    /**
    399     * A convenience method to send the FTP CDUP command to the server, receive the reply, and return the reply code.
    400     *
    401     * @return The reply code received from the server.
    402     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    403     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    404     *                                      independently as itself.
    405     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    406     */
    407    public int cdup() throws IOException {
    408        return sendCommand(FTPCmd.CDUP);
    409    }
    410
    411    /**
    412     * A convenience method to send the FTP CWD command to the server, receive the reply, and return the reply code.
    413     *
    414     * @param directory The new working directory.
    415     * @return The reply code received from the server.
    416     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    417     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    418     *                                      independently as itself.
    419     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    420     */
    421    public int cwd(final String directory) throws IOException {
    422        return sendCommand(FTPCmd.CWD, directory);
    423    }
    424
    425    /**
    426     * A convenience method to send the FTP DELE command to the server, receive the reply, and return the reply code.
    427     *
    428     * @param pathname The pathname to delete.
    429     * @return The reply code received from the server.
    430     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    431     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    432     *                                      independently as itself.
    433     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    434     */
    435    public int dele(final String pathname) throws IOException {
    436        return sendCommand(FTPCmd.DELE, pathname);
    437    }
    438
    439    /**
    440     * Closes the control connection to the FTP server and sets to null some internal data so that the memory may be reclaimed by the garbage collector. The
    441     * reply text and code information from the last command is voided so that the memory it used may be reclaimed. Also sets {@link #_controlInput_} and
    442     * {@link #_controlOutput_} to null.
    443     *
    444     * @throws IOException If an error occurs while disconnecting.
    445     */
    446    @Override
    447    public void disconnect() throws IOException {
    448        super.disconnect();
    449        _controlInput_ = null;
    450        _controlOutput_ = null;
    451        _newReplyString = false;
    452        _replyString = null;
    453    }
    454
    455    /**
    456     * A convenience method to send the FTP EPRT command to the server, receive the reply, and return the reply code.
    457     *
    458     * Examples:
    459     * <ul>
    460     * <li>EPRT |1|132.235.1.2|6275|</li>
    461     * <li>EPRT |2|1080::8:800:200C:417A|5282|</li>
    462     * </ul>
    463     *
    464     * @see "http://www.faqs.org/rfcs/rfc2428.html"
    465     *
    466     * @param host The host owning the port.
    467     * @param port The new port.
    468     * @return The reply code received from the server.
    469     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    470     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    471     *                                      independently as itself.
    472     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    473     * @since 2.2
    474     */
    475    public int eprt(final InetAddress host, final int port) throws IOException {
    476        final int num;
    477        final StringBuilder info = new StringBuilder();
    478        String h;
    479
    480        // If IPv6, trim the zone index
    481        h = host.getHostAddress();
    482        num = h.indexOf('%');
    483        if (num > 0) {
    484            h = h.substring(0, num);
    485        }
    486
    487        info.append("|");
    488
    489        if (host instanceof Inet4Address) {
    490            info.append("1");
    491        } else if (host instanceof Inet6Address) {
    492            info.append("2");
    493        }
    494        info.append("|");
    495        info.append(h);
    496        info.append("|");
    497        info.append(port);
    498        info.append("|");
    499
    500        return sendCommand(FTPCmd.EPRT, info.toString());
    501    }
    502
    503    /**
    504     * A convenience method to send the FTP EPSV command to the server, receive the reply, and return the reply code. Remember, it's up to you to interpret the
    505     * reply string containing the host/port information.
    506     *
    507     * @return The reply code received from the server.
    508     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    509     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    510     *                                      independently as itself.
    511     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    512     * @since 2.2
    513     */
    514    public int epsv() throws IOException {
    515        return sendCommand(FTPCmd.EPSV);
    516    }
    517
    518    /**
    519     * A convenience method to send the FTP FEAT command to the server, receive the reply, and return the reply code.
    520     *
    521     * @return The reply code received by the server
    522     * @throws IOException If an I/O error occurs while either sending the command or receiving the server reply.
    523     * @since 2.2
    524     */
    525    public int feat() throws IOException {
    526        return sendCommand(FTPCmd.FEAT);
    527    }
    528
    529    /**
    530     * Provide command support to super-class
    531     */
    532    @Override
    533    protected ProtocolCommandSupport getCommandSupport() {
    534        return _commandSupport_;
    535    }
    536
    537    /**
    538     * @return The character encoding used to communicate over the control connection.
    539     */
    540    public String getControlEncoding() {
    541        return _controlEncoding;
    542    }
    543
    544    /**
    545     * Fetches a reply from the FTP server and returns the integer reply code. After calling this method, the actual reply text can be accessed from either
    546     * calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }. Only use this method if you are implementing your own FTP
    547     * client or if you need to fetch a secondary response from the FTP server.
    548     *
    549     * @return The integer value of the reply code of the fetched FTP reply.
    550     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    551     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    552     *                                      independently as itself.
    553     * @throws IOException                  If an I/O error occurs while receiving the server reply.
    554     */
    555    public int getReply() throws IOException {
    556        return getReply(true);
    557    }
    558
    559    private int getReply(final boolean reportReply) throws IOException {
    560        final int length;
    561
    562        _newReplyString = true;
    563        _replyLines.clear();
    564
    565        String line = _controlInput_.readLine();
    566
    567        if (line == null) {
    568            throw new FTPConnectionClosedException("Connection closed without indication.");
    569        }
    570
    571        // In case we run into an anomaly we don't want fatal index exceptions
    572        // to be thrown.
    573        length = line.length();
    574        if (length < REPLY_CODE_LEN) {
    575            throw new MalformedServerReplyException("Truncated server reply: " + line);
    576        }
    577
    578        String code = null;
    579        try {
    580            code = line.substring(0, REPLY_CODE_LEN);
    581            _replyCode = Integer.parseInt(code);
    582        } catch (final NumberFormatException e) {
    583            throw new MalformedServerReplyException("Could not parse response code.\nServer Reply: " + line);
    584        }
    585
    586        _replyLines.add(line);
    587
    588        // Check the server reply type
    589        if (length > REPLY_CODE_LEN) {
    590            final char sep = line.charAt(REPLY_CODE_LEN);
    591            // Get extra lines if message continues.
    592            if (sep == '-') {
    593                do {
    594                    line = _controlInput_.readLine();
    595
    596                    if (line == null) {
    597                        throw new FTPConnectionClosedException("Connection closed without indication.");
    598                    }
    599
    600                    _replyLines.add(line);
    601
    602                    // The length() check handles problems that could arise from readLine()
    603                    // returning too soon after encountering a naked CR or some other
    604                    // anomaly.
    605                } while (isStrictMultilineParsing() ? strictCheck(line, code) : lenientCheck(line));
    606
    607            } else if (isStrictReplyParsing()) {
    608                if (length == REPLY_CODE_LEN + 1) { // expecting some text
    609                    throw new MalformedServerReplyException("Truncated server reply: '" + line + "'");
    610                }
    611                if (sep != ' ') {
    612                    throw new MalformedServerReplyException("Invalid server reply: '" + line + "'");
    613                }
    614            }
    615        } else if (isStrictReplyParsing()) {
    616            throw new MalformedServerReplyException("Truncated server reply: '" + line + "'");
    617        }
    618
    619        if (reportReply) {
    620            fireReplyReceived(_replyCode, getReplyString());
    621        }
    622
    623        if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) {
    624            throw new FTPConnectionClosedException("FTP response 421 received.  Server closed connection.");
    625        }
    626        return _replyCode;
    627    }
    628
    629    /**
    630     * Returns the integer value of the reply code of the last FTP reply. You will usually only use this method after you connect to the FTP server to check
    631     * that the connection was successful since <code> connect </code> is of type void.
    632     *
    633     * @return The integer value of the reply code of the last FTP reply.
    634     */
    635    public int getReplyCode() {
    636        return _replyCode;
    637    }
    638
    639    /**
    640     * Returns the entire text of the last FTP server response exactly as it was received, including all end of line markers in NETASCII format.
    641     *
    642     * @return The entire text from the last FTP response as a String.
    643     */
    644    public String getReplyString() {
    645        final StringBuilder buffer;
    646
    647        if (!_newReplyString) {
    648            return _replyString;
    649        }
    650
    651        buffer = new StringBuilder(256);
    652
    653        for (final String line : _replyLines) {
    654            buffer.append(line);
    655            buffer.append(SocketClient.NETASCII_EOL);
    656        }
    657
    658        _newReplyString = false;
    659
    660        return _replyString = buffer.toString();
    661    }
    662
    663    /**
    664     * Returns the nth line of text from the last FTP server response as a string. The end of line markers of each are stripped from the line.
    665     *
    666     * @param index The index of the line to return, 0-based.
    667     *
    668     * @return The lines of text from the last FTP response as an array.
    669     */
    670    String getReplyString(final int index) {
    671        return _replyLines.get(index);
    672    }
    673
    674    /**
    675     * Returns the lines of text from the last FTP server response as an array of strings, one entry per line. The end of line markers of each are stripped from
    676     * each line.
    677     *
    678     * @return The lines of text from the last FTP response as an array.
    679     */
    680    public String[] getReplyStrings() {
    681        return _replyLines.toArray(NetConstants.EMPTY_STRING_ARRAY);
    682    }
    683
    684    /**
    685     * A convenience method to send the FTP HELP command to the server, receive the reply, and return the reply code.
    686     *
    687     * @return The reply code received from the server.
    688     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    689     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    690     *                                      independently as itself.
    691     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    692     */
    693    public int help() throws IOException {
    694        return sendCommand(FTPCmd.HELP);
    695    }
    696
    697    /**
    698     * A convenience method to send the FTP HELP command to the server, receive the reply, and return the reply code.
    699     *
    700     * @param command The command name on which to request help.
    701     * @return The reply code received from the server.
    702     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    703     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    704     *                                      independently as itself.
    705     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    706     */
    707    public int help(final String command) throws IOException {
    708        return sendCommand(FTPCmd.HELP, command);
    709    }
    710
    711    /**
    712     * Return whether strict multiline parsing is enabled, as per RFC 959, section 4.2.
    713     *
    714     * @return True if strict, false if lenient
    715     * @since 2.0
    716     */
    717    public boolean isStrictMultilineParsing() {
    718        return strictMultilineParsing;
    719    }
    720
    721    /**
    722     * Return whether strict non-multiline parsing is enabled, as per RFC 959, section 4.2.
    723     * <p>
    724     * The default is true, which requires the 3 digit code be followed by space and some text. <br>
    725     * If false, only the 3 digit code is required (as was the case for versions up to 3.5) <br>
    726     *
    727     * @return True if strict (default), false if additional checks are not made
    728     * @since 3.6
    729     */
    730    public boolean isStrictReplyParsing() {
    731        return strictReplyParsing;
    732    }
    733
    734    // The strict check is too strong a condition because of non-conforming ftp
    735    // servers like ftp.funet.fi which sent 226 as the last line of a
    736    // 426 multi-line reply in response to ls /. We relax the condition to
    737    // test that the line starts with a digit rather than starting with
    738    // the code.
    739    private boolean lenientCheck(final String line) {
    740        return !(line.length() > REPLY_CODE_LEN && line.charAt(REPLY_CODE_LEN) != '-' && Character.isDigit(line.charAt(0)));
    741    }
    742
    743    /**
    744     * A convenience method to send the FTP LIST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    745     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    746     * for you.
    747     *
    748     * @return The reply code received from the server.
    749     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    750     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    751     *                                      independently as itself.
    752     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    753     */
    754    public int list() throws IOException {
    755        return sendCommand(FTPCmd.LIST);
    756    }
    757
    758    /**
    759     * A convenience method to send the FTP LIST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    760     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    761     * for you.
    762     *
    763     * @param pathname The pathname to list, may be {@code null} in which case the command is sent with no parameters
    764     * @return The reply code received from the server.
    765     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    766     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    767     *                                      independently as itself.
    768     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    769     */
    770    public int list(final String pathname) throws IOException {
    771        return sendCommand(FTPCmd.LIST, pathname);
    772    }
    773
    774    /**
    775     * Sends the MDTM command for the given file.
    776     *
    777     * @param file name of file
    778     * @return the status
    779     * @throws IOException on error
    780     * @since 2.0
    781     **/
    782    public int mdtm(final String file) throws IOException {
    783        return sendCommand(FTPCmd.MDTM, file);
    784    }
    785
    786    /**
    787     * A convenience method to send the FTP MFMT command to the server, receive the reply, and return the reply code.
    788     *
    789     * @param pathname The pathname for which mtime is to be changed
    790     * @param timeval  Timestamp in <code>yyyyMMDDhhmmss</code> format
    791     * @return The reply code received from the server.
    792     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    793     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    794     *                                      independently as itself.
    795     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    796     * @since 2.2
    797     * @see <a href="http://tools.ietf.org/html/draft-somers-ftp-mfxx-04">http://tools.ietf.org/html/draft-somers-ftp-mfxx-04</a>
    798     **/
    799    public int mfmt(final String pathname, final String timeval) throws IOException {
    800        return sendCommand(FTPCmd.MFMT, timeval + " " + pathname);
    801    }
    802
    803    /**
    804     * A convenience method to send the FTP MKD command to the server, receive the reply, and return the reply code.
    805     *
    806     * @param pathname The pathname of the new directory to create.
    807     * @return The reply code received from the server.
    808     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    809     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    810     *                                      independently as itself.
    811     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    812     */
    813    public int mkd(final String pathname) throws IOException {
    814        return sendCommand(FTPCmd.MKD, pathname);
    815    }
    816
    817    /**
    818     * A convenience method to send the FTP MLSD command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    819     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    820     * for you.
    821     *
    822     * @return The reply code received from the server.
    823     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    824     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    825     *                                      independently as itself.
    826     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    827     * @since 3.0
    828     */
    829    public int mlsd() throws IOException {
    830        return sendCommand(FTPCmd.MLSD);
    831    }
    832
    833    /**
    834     * A convenience method to send the FTP MLSD command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    835     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    836     * for you.
    837     *
    838     * @param path the path to report on
    839     * @return The reply code received from the server, may be {@code null} in which case the command is sent with no parameters
    840     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    841     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    842     *                                      independently as itself.
    843     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    844     * @since 3.0
    845     */
    846    public int mlsd(final String path) throws IOException {
    847        return sendCommand(FTPCmd.MLSD, path);
    848    }
    849
    850    /**
    851     * A convenience method to send the FTP MLST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    852     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    853     * for you.
    854     *
    855     * @return The reply code received from the server.
    856     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    857     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    858     *                                      independently as itself.
    859     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    860     * @since 3.0
    861     */
    862    public int mlst() throws IOException {
    863        return sendCommand(FTPCmd.MLST);
    864    }
    865
    866    /**
    867     * A convenience method to send the FTP MLST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    868     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    869     * for you.
    870     *
    871     * @param path the path to report on
    872     * @return The reply code received from the server, may be {@code null} in which case the command is sent with no parameters
    873     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    874     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    875     *                                      independently as itself.
    876     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    877     * @since 3.0
    878     */
    879    public int mlst(final String path) throws IOException {
    880        return sendCommand(FTPCmd.MLST, path);
    881    }
    882
    883    /**
    884     * A convenience method to send the FTP MODE command to the server, receive the reply, and return the reply code.
    885     *
    886     * @param mode The transfer mode to use (one of the <code>TRANSFER_MODE</code> constants).
    887     * @return The reply code received from the server.
    888     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    889     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    890     *                                      independently as itself.
    891     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    892     */
    893    public int mode(final int mode) throws IOException {
    894        return sendCommand(FTPCmd.MODE, modes.substring(mode, mode + 1));
    895    }
    896
    897    /**
    898     * A convenience method to send the FTP NLST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    899     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    900     * for you.
    901     *
    902     * @return The reply code received from the server.
    903     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    904     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    905     *                                      independently as itself.
    906     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    907     */
    908    public int nlst() throws IOException {
    909        return sendCommand(FTPCmd.NLST);
    910    }
    911
    912    /**
    913     * A convenience method to send the FTP NLST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    914     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    915     * for you.
    916     *
    917     * @param pathname The pathname to list, may be {@code null} in which case the command is sent with no parameters
    918     * @return The reply code received from the server.
    919     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    920     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    921     *                                      independently as itself.
    922     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    923     */
    924    public int nlst(final String pathname) throws IOException {
    925        return sendCommand(FTPCmd.NLST, pathname);
    926    }
    927
    928    /**
    929     * A convenience method to send the FTP NOOP command to the server, receive the reply, and return the reply code.
    930     *
    931     * @return The reply code received from the server.
    932     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    933     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    934     *                                      independently as itself.
    935     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    936     */
    937    public int noop() throws IOException {
    938        return sendCommand(FTPCmd.NOOP);
    939    }
    940
    941    /**
    942     * A convenience method to send the FTP PASS command to the server, receive the reply, and return the reply code.
    943     *
    944     * @param password The plain text password of the username being logged into.
    945     * @return The reply code received from the server.
    946     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    947     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    948     *                                      independently as itself.
    949     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    950     */
    951    public int pass(final String password) throws IOException {
    952        return sendCommand(FTPCmd.PASS, password);
    953    }
    954
    955    /**
    956     * A convenience method to send the FTP PASV command to the server, receive the reply, and return the reply code. Remember, it's up to you to interpret the
    957     * reply string containing the host/port information.
    958     *
    959     * @return The reply code received from the server.
    960     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    961     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    962     *                                      independently as itself.
    963     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    964     */
    965    public int pasv() throws IOException {
    966        return sendCommand(FTPCmd.PASV);
    967    }
    968
    969    /**
    970     * A convenience method to send the FTP PORT command to the server, receive the reply, and return the reply code.
    971     *
    972     * @param host The host owning the port.
    973     * @param port The new port.
    974     * @return The reply code received from the server.
    975     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    976     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    977     *                                      independently as itself.
    978     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    979     */
    980    public int port(final InetAddress host, final int port) throws IOException {
    981        int num;
    982        final StringBuilder info = new StringBuilder(24);
    983
    984        info.append(host.getHostAddress().replace('.', ','));
    985        num = port >>> 8;
    986        info.append(',');
    987        info.append(num);
    988        info.append(',');
    989        num = port & 0xff;
    990        info.append(num);
    991
    992        return sendCommand(FTPCmd.PORT, info.toString());
    993    }
    994
    995    /**
    996     * A convenience method to send the FTP PWD command to the server, receive the reply, and return the reply code.
    997     *
    998     * @return The reply code received from the server.
    999     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1000     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1001     *                                      independently as itself.
    1002     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1003     */
    1004    public int pwd() throws IOException {
    1005        return sendCommand(FTPCmd.PWD);
    1006    }
    1007
    1008    /**
    1009     * A convenience method to send the FTP QUIT command to the server, receive the reply, and return the reply code.
    1010     *
    1011     * @return The reply code received from the server.
    1012     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1013     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1014     *                                      independently as itself.
    1015     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1016     */
    1017    public int quit() throws IOException {
    1018        return sendCommand(FTPCmd.QUIT);
    1019    }
    1020
    1021    /**
    1022     * A convenience method to send the FTP REIN command to the server, receive the reply, and return the reply code.
    1023     *
    1024     * @return The reply code received from the server.
    1025     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1026     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1027     *                                      independently as itself.
    1028     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1029     */
    1030    public int rein() throws IOException {
    1031        return sendCommand(FTPCmd.REIN);
    1032    }
    1033
    1034    /**
    1035     * A convenience method to send the FTP REST command to the server, receive the reply, and return the reply code.
    1036     *
    1037     * @param marker The marker at which to restart a transfer.
    1038     * @return The reply code received from the server.
    1039     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1040     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1041     *                                      independently as itself.
    1042     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1043     */
    1044    public int rest(final String marker) throws IOException {
    1045        return sendCommand(FTPCmd.REST, marker);
    1046    }
    1047
    1048    /**
    1049     * A convenience method to send the FTP RETR command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    1050     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    1051     * for you.
    1052     *
    1053     * @param pathname The pathname of the file to retrieve.
    1054     * @return The reply code received from the server.
    1055     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1056     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1057     *                                      independently as itself.
    1058     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1059     */
    1060    public int retr(final String pathname) throws IOException {
    1061        return sendCommand(FTPCmd.RETR, pathname);
    1062    }
    1063
    1064    /**
    1065     * A convenience method to send the FTP RMD command to the server, receive the reply, and return the reply code.
    1066     *
    1067     * @param pathname The pathname of the directory to remove.
    1068     * @return The reply code received from the server.
    1069     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1070     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1071     *                                      independently as itself.
    1072     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1073     */
    1074    public int rmd(final String pathname) throws IOException {
    1075        return sendCommand(FTPCmd.RMD, pathname);
    1076    }
    1077
    1078    /**
    1079     * A convenience method to send the FTP RNFR command to the server, receive the reply, and return the reply code.
    1080     *
    1081     * @param pathname The pathname to rename from.
    1082     * @return The reply code received from the server.
    1083     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1084     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1085     *                                      independently as itself.
    1086     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1087     */
    1088    public int rnfr(final String pathname) throws IOException {
    1089        return sendCommand(FTPCmd.RNFR, pathname);
    1090    }
    1091
    1092    /**
    1093     * A convenience method to send the FTP RNTO command to the server, receive the reply, and return the reply code.
    1094     *
    1095     * @param pathname The pathname to rename to
    1096     * @return The reply code received from the server.
    1097     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1098     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1099     *                                      independently as itself.
    1100     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1101     */
    1102    public int rnto(final String pathname) throws IOException {
    1103        return sendCommand(FTPCmd.RNTO, pathname);
    1104    }
    1105
    1106    private void send(final String message) throws IOException, FTPConnectionClosedException, SocketException {
    1107        try {
    1108            _controlOutput_.write(message);
    1109            _controlOutput_.flush();
    1110        } catch (final SocketException e) {
    1111            if (!isConnected()) {
    1112                throw new FTPConnectionClosedException("Connection unexpectedly closed.");
    1113            }
    1114            throw e;
    1115        }
    1116    }
    1117
    1118    /**
    1119     * Sends an FTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
    1120     * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
    1121     *
    1122     * @param command The FTPCmd enum corresponding to the FTP command to send.
    1123     * @return The integer value of the FTP reply code returned by the server in response to the command.
    1124     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1125     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1126     *                                      independently as itself.
    1127     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1128     * @since 3.3
    1129     */
    1130    public int sendCommand(final FTPCmd command) throws IOException {
    1131        return sendCommand(command, null);
    1132    }
    1133
    1134    /**
    1135     * Sends an FTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
    1136     * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
    1137     *
    1138     * @param command The FTPCmd enum corresponding to the FTP command to send.
    1139     * @param args    The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
    1140     * @return The integer value of the FTP reply code returned by the server in response to the command.
    1141     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1142     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1143     *                                      independently as itself.
    1144     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1145     * @since 3.3
    1146     */
    1147    public int sendCommand(final FTPCmd command, final String args) throws IOException {
    1148        return sendCommand(command.getCommand(), args);
    1149    }
    1150
    1151    /**
    1152     * Sends an FTP command with no arguments to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed
    1153     * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
    1154     *
    1155     * @param command The FTPCommand constant corresponding to the FTP command to send.
    1156     * @return The integer value of the FTP reply code returned by the server in response to the command.
    1157     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1158     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1159     *                                      independently as itself.
    1160     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1161     */
    1162    public int sendCommand(final int command) throws IOException {
    1163        return sendCommand(command, null);
    1164    }
    1165
    1166    /**
    1167     * Sends an FTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
    1168     * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
    1169     *
    1170     * @param command The FTPCommand constant corresponding to the FTP command to send.
    1171     * @param args    The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
    1172     * @return The integer value of the FTP reply code returned by the server in response to the command.
    1173     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1174     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1175     *                                      independently as itself.
    1176     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1177     * @deprecated (3.3) Use {@link #sendCommand(FTPCmd, String)} instead
    1178     */
    1179    @Deprecated
    1180    public int sendCommand(final int command, final String args) throws IOException {
    1181        return sendCommand(FTPCommand.getCommand(command), args);
    1182    }
    1183
    1184    /**
    1185     * Sends an FTP command with no arguments to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed
    1186     * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
    1187     *
    1188     * @param command The text representation of the FTP command to send.
    1189     * @return The integer value of the FTP reply code returned by the server in response to the command.
    1190     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1191     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1192     *                                      independently as itself.
    1193     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1194     */
    1195    public int sendCommand(final String command) throws IOException {
    1196        return sendCommand(command, null);
    1197    }
    1198
    1199    /**
    1200     * Sends an FTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
    1201     * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
    1202     *
    1203     * @param command The text representation of the FTP command to send.
    1204     * @param args    The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
    1205     * @return The integer value of the FTP reply code returned by the server in response to the command.
    1206     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1207     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1208     *                                      independently as itself.
    1209     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1210     */
    1211    public int sendCommand(final String command, final String args) throws IOException {
    1212        if (_controlOutput_ == null) {
    1213            throw new IOException("Connection is not open");
    1214        }
    1215
    1216        final String message = buildMessage(command, args);
    1217
    1218        send(message);
    1219
    1220        fireCommandSent(command, message);
    1221
    1222        return getReply();
    1223    }
    1224
    1225    /**
    1226     * Saves the character encoding to be used by the FTP control connection. Some FTP servers require that commands be issued in a non-ASCII encoding like
    1227     * UTF-8 so that file names with multi-byte character representations (e.g, Big 8) can be specified.
    1228     * <p>
    1229     * Please note that this has to be set before the connection is established.
    1230     *
    1231     * @param encoding The new character encoding for the control connection.
    1232     */
    1233    public void setControlEncoding(final String encoding) {
    1234        _controlEncoding = encoding;
    1235    }
    1236
    1237    /**
    1238     * Set strict multiline parsing.
    1239     *
    1240     * @param strictMultilineParsing the setting
    1241     * @since 2.0
    1242     */
    1243    public void setStrictMultilineParsing(final boolean strictMultilineParsing) {
    1244        this.strictMultilineParsing = strictMultilineParsing;
    1245    }
    1246
    1247    /**
    1248     * Set strict non-multiline parsing.
    1249     * <p>
    1250     * If true, it requires the 3 digit code be followed by space and some text. <br>
    1251     * If false, only the 3 digit code is required (as was the case for versions up to 3.5)
    1252     * <p>
    1253     * <b>This should not be required by a well-behaved FTP server</b> <br>
    1254     *
    1255     * @param strictReplyParsing the setting
    1256     * @since 3.6
    1257     */
    1258    public void setStrictReplyParsing(final boolean strictReplyParsing) {
    1259        this.strictReplyParsing = strictReplyParsing;
    1260    }
    1261
    1262    /**
    1263     * A convenience method to send the FTP SITE command to the server, receive the reply, and return the reply code.
    1264     *
    1265     * @param parameters The site parameters to send.
    1266     * @return The reply code received from the server.
    1267     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1268     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1269     *                                      independently as itself.
    1270     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1271     */
    1272    public int site(final String parameters) throws IOException {
    1273        return sendCommand(FTPCmd.SITE, parameters);
    1274    }
    1275
    1276    /**
    1277     * A convenience method to send the FTP SIZE command to the server, receive the reply, and return the reply code.
    1278     *
    1279     * @param parameters The site parameters to send.
    1280     * @return The reply code received from the server.
    1281     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1282     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1283     *                                      independently as itself.
    1284     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1285     * @since 3.7
    1286     */
    1287    public int size(final String parameters) throws IOException {
    1288        return sendCommand(FTPCmd.SIZE, parameters);
    1289    }
    1290
    1291    /**
    1292     * A convenience method to send the FTP SMNT command to the server, receive the reply, and return the reply code.
    1293     *
    1294     * @param dir The directory name.
    1295     * @return The reply code received from the server.
    1296     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1297     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1298     *                                      independently as itself.
    1299     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1300     */
    1301    public int smnt(final String dir) throws IOException {
    1302        return sendCommand(FTPCmd.SMNT, dir);
    1303    }
    1304
    1305    /**
    1306     * A convenience method to send the FTP STAT command to the server, receive the reply, and return the reply code.
    1307     *
    1308     * @return The reply code received from the server.
    1309     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1310     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1311     *                                      independently as itself.
    1312     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1313     */
    1314    public int stat() throws IOException {
    1315        return sendCommand(FTPCmd.STAT);
    1316    }
    1317
    1318    /**
    1319     * A convenience method to send the FTP STAT command to the server, receive the reply, and return the reply code.
    1320     *
    1321     * @param pathname A pathname to list.
    1322     * @return The reply code received from the server.
    1323     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1324     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1325     *                                      independently as itself.
    1326     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1327     */
    1328    public int stat(final String pathname) throws IOException {
    1329        return sendCommand(FTPCmd.STAT, pathname);
    1330    }
    1331
    1332    /**
    1333     * A convenience method to send the FTP STOR command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    1334     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    1335     * for you.
    1336     *
    1337     * @param pathname The pathname to use for the file when stored at the remote end of the transfer.
    1338     * @return The reply code received from the server.
    1339     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1340     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1341     *                                      independently as itself.
    1342     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1343     */
    1344    public int stor(final String pathname) throws IOException {
    1345        return sendCommand(FTPCmd.STOR, pathname);
    1346    }
    1347
    1348    /**
    1349     * A convenience method to send the FTP STOU command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    1350     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    1351     * for you.
    1352     *
    1353     * @return The reply code received from the server.
    1354     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1355     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1356     *                                      independently as itself.
    1357     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1358     */
    1359    public int stou() throws IOException {
    1360        return sendCommand(FTPCmd.STOU);
    1361    }
    1362
    1363    /**
    1364     * A convenience method to send the FTP STOU command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
    1365     * data connection. If you don't need this low level of access, use {@link org.apache.commons.net.ftp.FTPClient} , which will handle all low level details
    1366     * for you.
    1367     *
    1368     * @param pathname The base pathname to use for the file when stored at the remote end of the transfer. Some FTP servers require this.
    1369     * @return The reply code received from the server.
    1370     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1371     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1372     *                                      independently as itself.
    1373     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1374     */
    1375    public int stou(final String pathname) throws IOException {
    1376        return sendCommand(FTPCmd.STOU, pathname);
    1377    }
    1378
    1379    // The RFC-compliant multiline termination check
    1380    private boolean strictCheck(final String line, final String code) {
    1381        return !(line.startsWith(code) && line.charAt(REPLY_CODE_LEN) == ' ');
    1382    }
    1383
    1384    /**
    1385     * A convenience method to send the FTP STRU command to the server, receive the reply, and return the reply code.
    1386     *
    1387     * @param structure The structure of the file (one of the <code>_STRUCTURE</code> constants).
    1388     * @return The reply code received from the server.
    1389     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1390     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1391     *                                      independently as itself.
    1392     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1393     */
    1394    public int stru(final int structure) throws IOException {
    1395        return sendCommand(FTPCmd.STRU, modes.substring(structure, structure + 1));
    1396    }
    1397
    1398    /**
    1399     * A convenience method to send the FTP SYST command to the server, receive the reply, and return the reply code.
    1400     *
    1401     * @return The reply code received from the server.
    1402     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1403     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1404     *                                      independently as itself.
    1405     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1406     */
    1407    public int syst() throws IOException {
    1408        return sendCommand(FTPCmd.SYST);
    1409    }
    1410
    1411    /**
    1412     * A convenience method to send the FTP TYPE command to the server, receive the reply, and return the reply code.
    1413     *
    1414     * @param fileType The type of the file (one of the <code>FILE_TYPE</code> constants).
    1415     * @return The reply code received from the server.
    1416     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1417     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1418     *                                      independently as itself.
    1419     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1420     */
    1421    public int type(final int fileType) throws IOException {
    1422        return sendCommand(FTPCmd.TYPE, modes.substring(fileType, fileType + 1));
    1423    }
    1424
    1425    /**
    1426     * A convenience method to send the FTP TYPE command for text files to the server, receive the reply, and return the reply code.
    1427     *
    1428     * @param fileType         The type of the file (one of the <code>FILE_TYPE</code> constants).
    1429     * @param formatOrByteSize The format of the file (one of the <code>_FORMAT</code> constants. In the case of <code>LOCAL_FILE_TYPE</code>, the byte size.
    1430     * @return The reply code received from the server.
    1431     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1432     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1433     *                                      independently as itself.
    1434     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1435     */
    1436    public int type(final int fileType, final int formatOrByteSize) throws IOException {
    1437        final StringBuilder arg = new StringBuilder();
    1438
    1439        arg.append(modes.charAt(fileType));
    1440        arg.append(' ');
    1441        if (fileType == LOCAL_FILE_TYPE) {
    1442            arg.append(formatOrByteSize);
    1443        } else {
    1444            arg.append(modes.charAt(formatOrByteSize));
    1445        }
    1446
    1447        return sendCommand(FTPCmd.TYPE, arg.toString());
    1448    }
    1449
    1450    /**
    1451     * A convenience method to send the FTP USER command to the server, receive the reply, and return the reply code.
    1452     *
    1453     * @param username The username to login under.
    1454     * @return The reply code received from the server.
    1455     * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
    1456     *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
    1457     *                                      independently as itself.
    1458     * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
    1459     */
    1460    public int user(final String username) throws IOException {
    1461        return sendCommand(FTPCmd.USER, username);
    1462    }
    1463}