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