FTP.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.net.ftp;

  18. import java.io.BufferedReader;
  19. import java.io.BufferedWriter;
  20. import java.io.IOException;
  21. import java.io.InputStreamReader;
  22. import java.io.OutputStreamWriter;
  23. import java.io.Reader;
  24. import java.net.Inet4Address;
  25. import java.net.Inet6Address;
  26. import java.net.InetAddress;
  27. import java.net.SocketException;
  28. import java.net.SocketTimeoutException;
  29. import java.nio.charset.StandardCharsets;
  30. import java.util.ArrayList;

  31. import org.apache.commons.net.MalformedServerReplyException;
  32. import org.apache.commons.net.ProtocolCommandSupport;
  33. import org.apache.commons.net.SocketClient;
  34. import org.apache.commons.net.io.CRLFLineReader;
  35. import org.apache.commons.net.util.NetConstants;

  36. /**
  37.  * FTP provides the basic the functionality necessary to implement your own FTP client. It extends org.apache.commons.net.SocketClient since extending
  38.  * TelnetClient was causing unwanted behavior (like connections that did not time out properly).
  39.  * <p>
  40.  * 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
  41.  * 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.
  42.  * 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
  43.  * 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
  44.  * this interaction.
  45.  * </p>
  46.  * <p>
  47.  * 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
  48.  * (usually 900 seconds). The FTP class will detect a premature FTP server connection closing when it receives a
  49.  * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } response to a command. When that occurs, the FTP class
  50.  * method encountering that reply will throw an {@link org.apache.commons.net.ftp.FTPConnectionClosedException}. <code>FTPConectionClosedException</code> is a
  51.  * subclass of <code>IOException</code> and therefore need not be caught separately, but if you are going to catch it separately, its catch block must appear
  52.  * before the more general <code>IOException</code> catch block. When you encounter an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} , you
  53.  * must disconnect the connection with {@link #disconnect disconnect() } to properly clean up the system resources used by FTP. Before disconnecting, you may
  54.  * check the last reply code and text with {@link #getReplyCode getReplyCode }, {@link #getReplyString getReplyString }, and {@link #getReplyStrings
  55.  * getReplyStrings}. You may avoid server disconnections while the client is idle by periodically sending NOOP commands to the server.
  56.  * </p>
  57.  * <p>
  58.  * 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
  59.  * {@link org.apache.commons.net.MalformedServerReplyException} , which is a subclass of IOException. A MalformedServerReplyException will be thrown when the
  60.  * 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
  61.  * lenient as possible.
  62.  * </p>
  63.  *
  64.  * @see FTPClient
  65.  * @see FTPConnectionClosedException
  66.  * @see org.apache.commons.net.MalformedServerReplyException
  67.  */

  68. public class FTP extends SocketClient {

  69.     /** The default FTP data port (20). */
  70.     public static final int DEFAULT_DATA_PORT = 20;

  71.     /** The default FTP control port (21). */
  72.     public static final int DEFAULT_PORT = 21;

  73.     /**
  74.      * 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
  75.      * <code>FILE_TYPE</code> are used to indicate file types.
  76.      */
  77.     public static final int ASCII_FILE_TYPE = 0;

  78.     /**
  79.      * A constant used to indicate the file(s) being transferred should be treated as EBCDIC. Note however that there are several EBCDIC formats. All
  80.      * constants ending in <code>FILE_TYPE</code> are used to indicate file types.
  81.      */
  82.     public static final int EBCDIC_FILE_TYPE = 1;

  83.     /**
  84.      * 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
  85.      * ending in <code>FILE_TYPE</code> are used to indicate file types.
  86.      */
  87.     public static final int BINARY_FILE_TYPE = 2;

  88.     /**
  89.      * A constant used to indicate the file(s) being transferred should be treated as a local type. All constants ending in <code>FILE_TYPE</code> are used to
  90.      * indicate file types.
  91.      */
  92.     public static final int LOCAL_FILE_TYPE = 3;

  93.     /**
  94.      * A constant used for text files to indicate a non-print text format. This is the default format. All constants ending in <code>TEXT_FORMAT</code> are used
  95.      * to indicate text formatting for text transfers (both ASCII and EBCDIC).
  96.      */
  97.     public static final int NON_PRINT_TEXT_FORMAT = 4;

  98.     /**
  99.      * A constant used to indicate a text file contains format vertical format control characters. All constants ending in <code>TEXT_FORMAT</code> are used to
  100.      * indicate text formatting for text transfers (both ASCII and EBCDIC).
  101.      */
  102.     public static final int TELNET_TEXT_FORMAT = 5;

  103.     /**
  104.      * A constant used to indicate a text file contains ASA vertical format control characters. All constants ending in <code>TEXT_FORMAT</code> are used to
  105.      * indicate text formatting for text transfers (both ASCII and EBCDIC).
  106.      */
  107.     public static final int CARRIAGE_CONTROL_TEXT_FORMAT = 6;

  108.     /**
  109.      * 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
  110.      * <code>_STRUCTURE</code> are used to indicate file structure for file transfers.
  111.      */
  112.     public static final int FILE_STRUCTURE = 7;

  113.     /**
  114.      * A constant used to indicate a file is to be treated as a sequence of records. All constants ending in <code>_STRUCTURE</code> are used to indicate file
  115.      * structure for file transfers.
  116.      */
  117.     public static final int RECORD_STRUCTURE = 8;

  118.     /**
  119.      * A constant used to indicate a file is to be treated as a set of independent indexed pages. All constants ending in <code>_STRUCTURE</code> are used to
  120.      * indicate file structure for file transfers.
  121.      */
  122.     public static final int PAGE_STRUCTURE = 9;

  123.     /**
  124.      * 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
  125.      * <code>TRANSFER_MODE</code> are used to indicate file transfer modes.
  126.      */
  127.     public static final int STREAM_TRANSFER_MODE = 10;

  128.     /**
  129.      * A constant used to indicate a file is to be transferred as a series of blocks. All constants ending in <code>TRANSFER_MODE</code> are used to indicate
  130.      * file transfer modes.
  131.      */
  132.     public static final int BLOCK_TRANSFER_MODE = 11;

  133.     /**
  134.      * A constant used to indicate a file is to be transferred as FTP compressed data. All constants ending in <code>TRANSFER_MODE</code> are used to indicate
  135.      * file transfer modes. Currently unused.
  136.      */
  137.     public static final int COMPRESSED_TRANSFER_MODE = 12;

  138.     /**
  139.      * 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
  140.      * <code>TRANSFER_MODE</code> are used to indicate file transfer modes.
  141.      *
  142.      * See the Internet Draft <a href="https://datatracker.ietf.org/doc/html/draft-preston-ftpext-deflate-04">Deflate transmission mode for FTP</a>
  143.      */
  144.     public static final int DEFLATE_TRANSFER_MODE = 13;

  145. //    /**
  146. //     * 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
  147. //     * <code>TRANSFER_MODE</code> are used to indicate file transfer modes.
  148. //     */
  149. //    public static final int GZIP_TRANSFER_MODE = 14;

  150.     // We have to ensure that the protocol communication is in ASCII,
  151.     // but we use ISO-8859-1 just in case 8-bit characters cross
  152.     // the wire.
  153.     /**
  154.      * The default character encoding used for communicating over an FTP control connection. The default encoding is an ASCII-compatible encoding. Some FTP
  155.      * servers expect other encodings. You can change the encoding used by an FTP instance with {@link #setControlEncoding setControlEncoding}.
  156.      */
  157.     public static final String DEFAULT_CONTROL_ENCODING = StandardCharsets.ISO_8859_1.name();

  158.     /** Length of the FTP reply code (3 alphanumerics) */
  159.     public static final int REPLY_CODE_LEN = 3;

  160.     private static final String MODES = "AEILNTCFRPSBCZ";
  161.     protected int _replyCode;
  162.     protected ArrayList<String> _replyLines;
  163.     protected boolean _newReplyString;
  164.     protected String _replyString;
  165.     protected String _controlEncoding;

  166.     /**
  167.      * A ProtocolCommandSupport object used to manage the registering of ProtocolCommandListeners and the firing of ProtocolCommandEvents.
  168.      */
  169.     protected ProtocolCommandSupport _commandSupport_;

  170.     /**
  171.      * 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
  172.      * 959 for details.
  173.      */
  174.     protected boolean strictMultilineParsing;

  175.     /**
  176.      * 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
  177.      * followed by space See section 4.2 of RFC 959 for details.
  178.      */
  179.     private boolean strictReplyParsing = true;

  180.     /**
  181.      * Wraps SocketClient._input_ to facilitate the reading of text from the FTP control connection. Do not access the control connection via
  182.      * SocketClient._input_. This member starts with a null value, is initialized in {@link #_connectAction_}, and set to null in {@link #disconnect}.
  183.      */
  184.     protected BufferedReader _controlInput_;

  185.     /**
  186.      * Wraps SocketClient._output_ to facilitate the writing of text to the FTP control connection. Do not access the control connection via
  187.      * SocketClient._output_. This member starts with a null value, is initialized in {@link #_connectAction_}, and set to null in {@link #disconnect}.
  188.      */
  189.     protected BufferedWriter _controlOutput_;

  190.     /**
  191.      * The default FTP constructor. Sets the default port to <code>DEFAULT_PORT</code> and initializes internal data structures for saving FTP reply
  192.      * information.
  193.      */
  194.     public FTP() {
  195.         setDefaultPort(DEFAULT_PORT);
  196.         _replyLines = new ArrayList<>();
  197.         _newReplyString = false;
  198.         _replyString = null;
  199.         _controlEncoding = DEFAULT_CONTROL_ENCODING;
  200.         _commandSupport_ = new ProtocolCommandSupport(this);
  201.     }

  202.     /**
  203.      * Gets the reply, but don't pass it to command listeners. Used for keep-alive processing only.
  204.      *
  205.      * @since 3.0
  206.      * @throws IOException on error
  207.      */
  208.     protected void __getReplyNoReport() throws IOException {
  209.         getReply(false);
  210.     }

  211.     /**
  212.      * Send a noop and get the reply without reporting to the command listener. Intended for use with keep-alive.
  213.      *
  214.      * @throws IOException on error
  215.      * @since 3.0
  216.      */
  217.     protected void __noop() throws IOException {
  218.         final String msg = buildMessage(FTPCmd.NOOP.getCommand(), null);
  219.         send(msg);
  220.         __getReplyNoReport(); // This may time out
  221.     }

  222.     /**
  223.      * Initiates control connections and gets initial reply. Initializes {@link #_controlInput_} and {@link #_controlOutput_}.
  224.      */
  225.     @Override
  226.     protected void _connectAction_() throws IOException {
  227.         _connectAction_(null);
  228.     }

  229.     /**
  230.      * Initiates control connections and gets initial reply. Initializes {@link #_controlInput_} and {@link #_controlOutput_}.
  231.      *
  232.      * @param socketIsReader the reader to reuse (if non-null)
  233.      * @throws IOException on error
  234.      * @since 3.4
  235.      */
  236.     protected void _connectAction_(final Reader socketIsReader) throws IOException {
  237.         super._connectAction_(); // sets up _input_ and _output_
  238.         if (socketIsReader == null) {
  239.             _controlInput_ = new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding()));
  240.         } else {
  241.             _controlInput_ = new CRLFLineReader(socketIsReader);
  242.         }
  243.         _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding()));
  244.         if (connectTimeout > 0) { // NET-385
  245.             final int original = _socket_.getSoTimeout();
  246.             _socket_.setSoTimeout(connectTimeout);
  247.             try {
  248.                 getReply();
  249.                 // If we received code 120, we have to fetch completion reply.
  250.                 if (FTPReply.isPositivePreliminary(_replyCode)) {
  251.                     getReply();
  252.                 }
  253.             } catch (final SocketTimeoutException e) {
  254.                 final IOException ioe = new IOException("Timed out waiting for initial connect reply");
  255.                 ioe.initCause(e);
  256.                 throw ioe;
  257.             } finally {
  258.                 _socket_.setSoTimeout(original);
  259.             }
  260.         } else {
  261.             getReply();
  262.             // If we received code 120, we have to fetch completion reply.
  263.             if (FTPReply.isPositivePreliminary(_replyCode)) {
  264.                 getReply();
  265.             }
  266.         }
  267.     }

  268.     /**
  269.      * A convenience method to send the FTP ABOR command to the server, receive the reply, and return the reply code.
  270.      *
  271.      * @return The reply code received from the server.
  272.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  273.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  274.      *                                      independently as itself.
  275.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  276.      */
  277.     public int abor() throws IOException {
  278.         return sendCommand(FTPCmd.ABOR);
  279.     }

  280.     /**
  281.      * A convenience method to send the FTP ACCT command to the server, receive the reply, and return the reply code.
  282.      *
  283.      * @param account The account name to access.
  284.      * @return The reply code received from the server.
  285.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  286.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  287.      *                                      independently as itself.
  288.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  289.      */
  290.     public int acct(final String account) throws IOException {
  291.         return sendCommand(FTPCmd.ACCT, account);
  292.     }

  293.     /**
  294.      * A convenience method to send the FTP ALLO command to the server, receive the reply, and return the reply code.
  295.      *
  296.      * @param bytes The number of bytes to allocate.
  297.      * @return The reply code received from the server.
  298.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  299.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  300.      *                                      independently as itself.
  301.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  302.      */
  303.     public int allo(final int bytes) throws IOException {
  304.         return sendCommand(FTPCmd.ALLO, Integer.toString(bytes));
  305.     }

  306.     /**
  307.      * A convenience method to send the FTP ALLO command to the server, receive the reply, and return the reply code.
  308.      *
  309.      * @param bytes      The number of bytes to allocate.
  310.      * @param recordSize The size of a record.
  311.      * @return The reply code received from the server.
  312.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  313.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  314.      *                                      independently as itself.
  315.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  316.      */
  317.     public int allo(final int bytes, final int recordSize) throws IOException {
  318.         return sendCommand(FTPCmd.ALLO, Integer.toString(bytes) + " R " + Integer.toString(recordSize));
  319.     }

  320.     /**
  321.      * A convenience method to send the FTP ALLO command to the server, receive the reply, and return the reply code.
  322.      *
  323.      * @param bytes The number of bytes to allocate.
  324.      * @return The reply code received from the server.
  325.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  326.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  327.      *                                      independently as itself.
  328.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  329.      */
  330.     public int allo(final long bytes) throws IOException {
  331.         return sendCommand(FTPCmd.ALLO, Long.toString(bytes));
  332.     }

  333.     /**
  334.      * A convenience method to send the FTP ALLO command to the server, receive the reply, and return the reply code.
  335.      *
  336.      * @param bytes      The number of bytes to allocate.
  337.      * @param recordSize The size of a record.
  338.      * @return The reply code received from the server.
  339.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  340.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  341.      *                                      independently as itself.
  342.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  343.      */
  344.     public int allo(final long bytes, final int recordSize) throws IOException {
  345.         return sendCommand(FTPCmd.ALLO, Long.toString(bytes) + " R " + Integer.toString(recordSize));
  346.     }

  347.     /**
  348.      * A convenience method to send the FTP APPE command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  349.      * 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
  350.      * for you.
  351.      *
  352.      * @param pathname The pathname to use for the file when stored at the remote end of the transfer.
  353.      * @return The reply code received from the server.
  354.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  355.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  356.      *                                      independently as itself.
  357.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  358.      */
  359.     public int appe(final String pathname) throws IOException {
  360.         return sendCommand(FTPCmd.APPE, pathname);
  361.     }

  362.     private String buildMessage(final String command, final String args) {
  363.         final StringBuilder __commandBuffer = new StringBuilder();
  364.         __commandBuffer.append(command);
  365.         if (args != null) {
  366.             __commandBuffer.append(' ');
  367.             __commandBuffer.append(args);
  368.         }
  369.         __commandBuffer.append(SocketClient.NETASCII_EOL);
  370.         return __commandBuffer.toString();
  371.     }

  372.     /**
  373.      * A convenience method to send the FTP CDUP command to the server, receive the reply, and return the reply code.
  374.      *
  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 cdup() throws IOException {
  382.         return sendCommand(FTPCmd.CDUP);
  383.     }

  384.     private int checkMode(final int index) {
  385.         if (index >= MODES.length()) {
  386.             throw new IllegalArgumentException("Unknown mode");
  387.         }
  388.         return index;
  389.     }

  390.     /**
  391.      * A convenience method to send the FTP CWD command to the server, receive the reply, and return the reply code.
  392.      *
  393.      * @param directory The new working directory.
  394.      * @return The reply code received from the server.
  395.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  396.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  397.      *                                      independently as itself.
  398.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  399.      */
  400.     public int cwd(final String directory) throws IOException {
  401.         return sendCommand(FTPCmd.CWD, directory);
  402.     }

  403.     /**
  404.      * A convenience method to send the FTP DELE command to the server, receive the reply, and return the reply code.
  405.      *
  406.      * @param pathname The pathname to delete.
  407.      * @return The reply code received from the server.
  408.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  409.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  410.      *                                      independently as itself.
  411.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  412.      */
  413.     public int dele(final String pathname) throws IOException {
  414.         return sendCommand(FTPCmd.DELE, pathname);
  415.     }

  416.     /**
  417.      * 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
  418.      * 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
  419.      * {@link #_controlOutput_} to null.
  420.      *
  421.      * @throws IOException If an error occurs while disconnecting.
  422.      */
  423.     @Override
  424.     public void disconnect() throws IOException {
  425.         super.disconnect();
  426.         _controlInput_ = null;
  427.         _controlOutput_ = null;
  428.         _newReplyString = false;
  429.         _replyString = null;
  430.     }

  431.     /**
  432.      * A convenience method to send the FTP EPRT command to the server, receive the reply, and return the reply code.
  433.      *
  434.      * Examples:
  435.      * <ul>
  436.      * <li>EPRT |1|132.235.1.2|6275|</li>
  437.      * <li>EPRT |2|1080::8:800:200C:417A|5282|</li>
  438.      * </ul>
  439.      *
  440.      * @see "http://www.faqs.org/rfcs/rfc2428.html"
  441.      *
  442.      * @param host The host owning the port.
  443.      * @param port The new port.
  444.      * @return The reply code received from the server.
  445.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  446.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  447.      *                                      independently as itself.
  448.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  449.      * @since 2.2
  450.      */
  451.     public int eprt(final InetAddress host, final int port) throws IOException {
  452.         final int num;
  453.         final StringBuilder info = new StringBuilder();
  454.         String h;

  455.         // If IPv6, trim the zone index
  456.         h = host.getHostAddress();
  457.         num = h.indexOf('%');
  458.         if (num > 0) {
  459.             h = h.substring(0, num);
  460.         }

  461.         info.append("|");

  462.         if (host instanceof Inet4Address) {
  463.             info.append("1");
  464.         } else if (host instanceof Inet6Address) {
  465.             info.append("2");
  466.         }
  467.         info.append("|");
  468.         info.append(h);
  469.         info.append("|");
  470.         info.append(port);
  471.         info.append("|");

  472.         return sendCommand(FTPCmd.EPRT, info.toString());
  473.     }

  474.     /**
  475.      * A convenience method to send the FTP EPSV command to the server, receive the reply, and return the reply code. Remember, it's up to you to interpret the
  476.      * reply string containing the host/port information.
  477.      *
  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.      * @since 2.2
  484.      */
  485.     public int epsv() throws IOException {
  486.         return sendCommand(FTPCmd.EPSV);
  487.     }

  488.     /**
  489.      * A convenience method to send the FTP FEAT command to the server, receive the reply, and return the reply code.
  490.      *
  491.      * @return The reply code received by the server
  492.      * @throws IOException If an I/O error occurs while either sending the command or receiving the server reply.
  493.      * @since 2.2
  494.      */
  495.     public int feat() throws IOException {
  496.         return sendCommand(FTPCmd.FEAT);
  497.     }

  498.     /**
  499.      * Provide command support to super-class
  500.      */
  501.     @Override
  502.     protected ProtocolCommandSupport getCommandSupport() {
  503.         return _commandSupport_;
  504.     }

  505.     /**
  506.      * @return The character encoding used to communicate over the control connection.
  507.      */
  508.     public String getControlEncoding() {
  509.         return _controlEncoding;
  510.     }

  511.     /**
  512.      * Fetches a reply from the FTP server and returns the integer reply code. After calling this method, the actual reply text can be accessed from either
  513.      * calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }. Only use this method if you are implementing your own FTP
  514.      * client or if you need to fetch a secondary response from the FTP server.
  515.      *
  516.      * @return The integer value of the reply code of the fetched FTP reply.
  517.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  518.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  519.      *                                      independently as itself.
  520.      * @throws IOException                  If an I/O error occurs while receiving the server reply.
  521.      */
  522.     public int getReply() throws IOException {
  523.         return getReply(true);
  524.     }

  525.     private int getReply(final boolean reportReply) throws IOException {
  526.         final int length;

  527.         _newReplyString = true;
  528.         _replyLines.clear();

  529.         String line = _controlInput_.readLine();

  530.         if (line == null) {
  531.             throw new FTPConnectionClosedException("Connection closed without indication.");
  532.         }

  533.         // In case we run into an anomaly we don't want fatal index exceptions
  534.         // to be thrown.
  535.         length = line.length();
  536.         if (length < REPLY_CODE_LEN) {
  537.             throw new MalformedServerReplyException("Truncated server reply: " + line);
  538.         }

  539.         String code;
  540.         try {
  541.             code = line.substring(0, REPLY_CODE_LEN);
  542.             _replyCode = Integer.parseInt(code);
  543.         } catch (final NumberFormatException e) {
  544.             throw new MalformedServerReplyException("Could not parse response code.\nServer Reply: " + line);
  545.         }

  546.         _replyLines.add(line);

  547.         // Check the server reply type
  548.         if (length > REPLY_CODE_LEN) {
  549.             final char sep = line.charAt(REPLY_CODE_LEN);
  550.             // Get extra lines if message continues.
  551.             if (sep == '-') {
  552.                 do {
  553.                     line = _controlInput_.readLine();

  554.                     if (line == null) {
  555.                         throw new FTPConnectionClosedException("Connection closed without indication.");
  556.                     }

  557.                     _replyLines.add(line);

  558.                     // The length() check handles problems that could arise from readLine()
  559.                     // returning too soon after encountering a naked CR or some other
  560.                     // anomaly.
  561.                 } while (isStrictMultilineParsing() ? strictCheck(line, code) : lenientCheck(line));

  562.             } else if (isStrictReplyParsing()) {
  563.                 if (length == REPLY_CODE_LEN + 1) { // expecting some text
  564.                     throw new MalformedServerReplyException("Truncated server reply: '" + line + "'");
  565.                 }
  566.                 if (sep != ' ') {
  567.                     throw new MalformedServerReplyException("Invalid server reply: '" + line + "'");
  568.                 }
  569.             }
  570.         } else if (isStrictReplyParsing()) {
  571.             throw new MalformedServerReplyException("Truncated server reply: '" + line + "'");
  572.         }

  573.         if (reportReply) {
  574.             fireReplyReceived(_replyCode, getReplyString());
  575.         }

  576.         if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) {
  577.             throw new FTPConnectionClosedException("FTP response 421 received.  Server closed connection.");
  578.         }
  579.         return _replyCode;
  580.     }

  581.     /**
  582.      * Returns the integer value of the reply code of the last FTP reply. You will usually only use this method after you connect to the FTP server to check
  583.      * that the connection was successful since <code>connect</code> is of type void.
  584.      *
  585.      * @return The integer value of the reply code of the last FTP reply.
  586.      */
  587.     public int getReplyCode() {
  588.         return _replyCode;
  589.     }

  590.     /**
  591.      * Returns the entire text of the last FTP server response exactly as it was received, including all end of line markers in NETASCII format.
  592.      *
  593.      * @return The entire text from the last FTP response as a String.
  594.      */
  595.     public String getReplyString() {
  596.         if (!_newReplyString) {
  597.             return _replyString;
  598.         }
  599.         final StringBuilder buffer = new StringBuilder(256);
  600.         for (final String line : _replyLines) {
  601.             buffer.append(line);
  602.             buffer.append(SocketClient.NETASCII_EOL);
  603.         }
  604.         _newReplyString = false;
  605.         return _replyString = buffer.toString();
  606.     }

  607.     /**
  608.      * Returns the nth line of text from the last FTP server response as a string. The end of line markers of each are stripped from the line.
  609.      *
  610.      * @param index The index of the line to return, 0-based.
  611.      *
  612.      * @return The lines of text from the last FTP response as an array.
  613.      */
  614.     String getReplyString(final int index) {
  615.         return _replyLines.get(index);
  616.     }

  617.     /**
  618.      * Returns the lines of text from the last FTP server response as an array of strings, one entry per line. The end of line markers of each are stripped from
  619.      * each line.
  620.      *
  621.      * @return The lines of text from the last FTP response as an array.
  622.      */
  623.     public String[] getReplyStrings() {
  624.         return _replyLines.toArray(NetConstants.EMPTY_STRING_ARRAY);
  625.     }

  626.     /**
  627.      * A convenience method to send the FTP HELP command to the server, receive the reply, and return the reply code.
  628.      *
  629.      * @return The reply code received from the server.
  630.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  631.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  632.      *                                      independently as itself.
  633.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  634.      */
  635.     public int help() throws IOException {
  636.         return sendCommand(FTPCmd.HELP);
  637.     }

  638.     /**
  639.      * A convenience method to send the FTP HELP command to the server, receive the reply, and return the reply code.
  640.      *
  641.      * @param command The command name on which to request help.
  642.      * @return The reply code received from the server.
  643.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  644.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  645.      *                                      independently as itself.
  646.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  647.      */
  648.     public int help(final String command) throws IOException {
  649.         return sendCommand(FTPCmd.HELP, command);
  650.     }

  651.     /**
  652.      * Return whether strict multiline parsing is enabled, as per RFC 959, section 4.2.
  653.      *
  654.      * @return True if strict, false if lenient
  655.      * @since 2.0
  656.      */
  657.     public boolean isStrictMultilineParsing() {
  658.         return strictMultilineParsing;
  659.     }

  660.     /**
  661.      * Return whether strict non-multiline parsing is enabled, as per RFC 959, section 4.2.
  662.      * <p>
  663.      * The default is true, which requires the 3-digit code be followed by space and some text. <br>
  664.      * If false, only the 3-digit code is required (as was the case for versions up to 3.5) <br>
  665.      *
  666.      * @return True if strict (default), false if additional checks are not made
  667.      * @since 3.6
  668.      */
  669.     public boolean isStrictReplyParsing() {
  670.         return strictReplyParsing;
  671.     }

  672.     // The strict check is too strong a condition because of non-conforming ftp
  673.     // servers like ftp.funet.fi which sent 226 as the last line of a
  674.     // 426 multi-line reply in response to ls /. We relax the condition to
  675.     // test that the line starts with a digit rather than starting with
  676.     // the code.
  677.     private boolean lenientCheck(final String line) {
  678.         return !(line.length() > REPLY_CODE_LEN && line.charAt(REPLY_CODE_LEN) != '-' && Character.isDigit(line.charAt(0)));
  679.     }

  680.     /**
  681.      * A convenience method to send the FTP LIST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  682.      * 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
  683.      * for you.
  684.      *
  685.      * @return The reply code received from the server.
  686.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  687.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  688.      *                                      independently as itself.
  689.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  690.      */
  691.     public int list() throws IOException {
  692.         return sendCommand(FTPCmd.LIST);
  693.     }

  694.     /**
  695.      * A convenience method to send the FTP LIST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  696.      * 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
  697.      * for you.
  698.      *
  699.      * @param pathname The pathname to list, may be {@code null} in which case the command is sent with no parameters
  700.      * @return The reply code received from the server.
  701.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  702.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  703.      *                                      independently as itself.
  704.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  705.      */
  706.     public int list(final String pathname) throws IOException {
  707.         return sendCommand(FTPCmd.LIST, pathname);
  708.     }

  709.     /**
  710.      * Sends the MDTM command for the given file.
  711.      *
  712.      * @param file name of file
  713.      * @return the status
  714.      * @throws IOException on error
  715.      * @since 2.0
  716.      **/
  717.     public int mdtm(final String file) throws IOException {
  718.         return sendCommand(FTPCmd.MDTM, file);
  719.     }

  720.     /**
  721.      * A convenience method to send the FTP MFMT command to the server, receive the reply, and return the reply code.
  722.      *
  723.      * @param pathname The pathname for which mtime is to be changed
  724.      * @param timeval  Timestamp in <code>yyyyMMDDhhmmss</code> format
  725.      * @return The reply code received from the server.
  726.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  727.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  728.      *                                      independently as itself.
  729.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  730.      * @since 2.2
  731.      * @see <a href="https://tools.ietf.org/html/draft-somers-ftp-mfxx-04">https://tools.ietf.org/html/draft-somers-ftp-mfxx-04</a>
  732.      **/
  733.     public int mfmt(final String pathname, final String timeval) throws IOException {
  734.         return sendCommand(FTPCmd.MFMT, timeval + " " + pathname);
  735.     }

  736.     /**
  737.      * A convenience method to send the FTP MKD command to the server, receive the reply, and return the reply code.
  738.      *
  739.      * @param pathname The pathname of the new directory to create.
  740.      * @return The reply code received from the server.
  741.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  742.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  743.      *                                      independently as itself.
  744.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  745.      */
  746.     public int mkd(final String pathname) throws IOException {
  747.         return sendCommand(FTPCmd.MKD, pathname);
  748.     }

  749.     /**
  750.      * A convenience method to send the FTP MLSD command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  751.      * 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
  752.      * for you.
  753.      *
  754.      * @return The reply code received from the server.
  755.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  756.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  757.      *                                      independently as itself.
  758.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  759.      * @since 3.0
  760.      */
  761.     public int mlsd() throws IOException {
  762.         return sendCommand(FTPCmd.MLSD);
  763.     }

  764.     /**
  765.      * A convenience method to send the FTP MLSD command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  766.      * 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
  767.      * for you.
  768.      *
  769.      * @param path the path to report on
  770.      * @return The reply code received from the server, may be {@code null} in which case the command is sent with no parameters
  771.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  772.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  773.      *                                      independently as itself.
  774.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  775.      * @since 3.0
  776.      */
  777.     public int mlsd(final String path) throws IOException {
  778.         return sendCommand(FTPCmd.MLSD, path);
  779.     }

  780.     /**
  781.      * A convenience method to send the FTP MLST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  782.      * 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
  783.      * for you.
  784.      *
  785.      * @return The reply code received from the server.
  786.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  787.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  788.      *                                      independently as itself.
  789.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  790.      * @since 3.0
  791.      */
  792.     public int mlst() throws IOException {
  793.         return sendCommand(FTPCmd.MLST);
  794.     }

  795.     /**
  796.      * A convenience method to send the FTP MLST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  797.      * 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
  798.      * for you.
  799.      *
  800.      * @param path the path to report on
  801.      * @return The reply code received from the server, may be {@code null} in which case the command is sent with no parameters
  802.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  803.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  804.      *                                      independently as itself.
  805.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  806.      * @since 3.0
  807.      */
  808.     public int mlst(final String path) throws IOException {
  809.         return sendCommand(FTPCmd.MLST, path);
  810.     }

  811.     /**
  812.      * A convenience method to send the FTP MODE command to the server, receive the reply, and return the reply code.
  813.      *
  814.      * @param mode The transfer mode to use (one of the <code>TRANSFER_MODE</code> constants).
  815.      * @return The reply code received from the server.
  816.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  817.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  818.      *                                      independently as itself.
  819.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  820.      */
  821.     public int mode(final int mode) throws IOException {

  822.         return sendCommand(FTPCmd.MODE, modeStringAt(mode));
  823.     }

  824.     private char modeCharAt(final int index) {
  825.         return MODES.charAt(checkMode(index));
  826.     }

  827.     private String modeStringAt(final int index) {
  828.         checkMode(index);
  829.         return MODES.substring(index, index + 1);
  830.     }

  831.     /**
  832.      * A convenience method to send the FTP NLST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  833.      * 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
  834.      * for you.
  835.      *
  836.      * @return The reply code received from the server.
  837.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  838.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  839.      *                                      independently as itself.
  840.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  841.      */
  842.     public int nlst() throws IOException {
  843.         return sendCommand(FTPCmd.NLST);
  844.     }

  845.     /**
  846.      * A convenience method to send the FTP NLST command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  847.      * 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
  848.      * for you.
  849.      *
  850.      * @param pathname The pathname to list, may be {@code null} in which case the command is sent with no parameters
  851.      * @return The reply code received from the server.
  852.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  853.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  854.      *                                      independently as itself.
  855.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  856.      */
  857.     public int nlst(final String pathname) throws IOException {
  858.         return sendCommand(FTPCmd.NLST, pathname);
  859.     }

  860.     /**
  861.      * A convenience method to send the FTP NOOP command to the server, receive the reply, and return the reply code.
  862.      *
  863.      * @return The reply code received from the server.
  864.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  865.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  866.      *                                      independently as itself.
  867.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  868.      */
  869.     public int noop() throws IOException {
  870.         return sendCommand(FTPCmd.NOOP);
  871.     }

  872.     /**
  873.      * A convenience method to send the FTP PASS command to the server, receive the reply, and return the reply code.
  874.      *
  875.      * @param password The plain text password of the user being logged into.
  876.      * @return The reply code received from the server.
  877.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  878.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  879.      *                                      independently as itself.
  880.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  881.      */
  882.     public int pass(final String password) throws IOException {
  883.         return sendCommand(FTPCmd.PASS, password);
  884.     }

  885.     /**
  886.      * A convenience method to send the FTP PASV command to the server, receive the reply, and return the reply code. Remember, it's up to you to interpret the
  887.      * reply string containing the host/port information.
  888.      *
  889.      * @return The reply code received from the server.
  890.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  891.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  892.      *                                      independently as itself.
  893.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  894.      */
  895.     public int pasv() throws IOException {
  896.         return sendCommand(FTPCmd.PASV);
  897.     }

  898.     /**
  899.      * A convenience method to send the FTP PORT command to the server, receive the reply, and return the reply code.
  900.      *
  901.      * @param host The host owning the port.
  902.      * @param port The new port.
  903.      * @return The reply code received from the server.
  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.      */
  909.     public int port(final InetAddress host, final int port) throws IOException {
  910.         int num;
  911.         final StringBuilder info = new StringBuilder(24);

  912.         info.append(host.getHostAddress().replace('.', ','));
  913.         num = port >>> 8;
  914.         info.append(',');
  915.         info.append(num);
  916.         info.append(',');
  917.         num = port & 0xff;
  918.         info.append(num);

  919.         return sendCommand(FTPCmd.PORT, info.toString());
  920.     }

  921.     /**
  922.      * A convenience method to send the FTP PWD command to the server, receive the reply, and return the reply code.
  923.      *
  924.      * @return The reply code received from the server.
  925.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  926.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  927.      *                                      independently as itself.
  928.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  929.      */
  930.     public int pwd() throws IOException {
  931.         return sendCommand(FTPCmd.PWD);
  932.     }

  933.     /**
  934.      * A convenience method to send the FTP QUIT command to the server, receive the reply, and return the reply code.
  935.      *
  936.      * @return The reply code received from the server.
  937.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  938.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  939.      *                                      independently as itself.
  940.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  941.      */
  942.     public int quit() throws IOException {
  943.         return sendCommand(FTPCmd.QUIT);
  944.     }

  945.     /**
  946.      * A convenience method to send the FTP REIN command to the server, receive the reply, and return the reply code.
  947.      *
  948.      * @return The reply code received from the server.
  949.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  950.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  951.      *                                      independently as itself.
  952.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  953.      */
  954.     public int rein() throws IOException {
  955.         return sendCommand(FTPCmd.REIN);
  956.     }

  957.     /**
  958.      * A convenience method to send the FTP REST command to the server, receive the reply, and return the reply code.
  959.      *
  960.      * @param marker The marker at which to restart a transfer.
  961.      * @return The reply code received from the server.
  962.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  963.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  964.      *                                      independently as itself.
  965.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  966.      */
  967.     public int rest(final String marker) throws IOException {
  968.         return sendCommand(FTPCmd.REST, marker);
  969.     }

  970.     /**
  971.      * A convenience method to send the FTP RETR command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  972.      * 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
  973.      * for you.
  974.      *
  975.      * @param pathname The pathname of the file to retrieve.
  976.      * @return The reply code received from the server.
  977.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  978.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  979.      *                                      independently as itself.
  980.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  981.      */
  982.     public int retr(final String pathname) throws IOException {
  983.         return sendCommand(FTPCmd.RETR, pathname);
  984.     }

  985.     /**
  986.      * A convenience method to send the FTP RMD command to the server, receive the reply, and return the reply code.
  987.      *
  988.      * @param pathname The pathname of the directory to remove.
  989.      * @return The reply code received from the server.
  990.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  991.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  992.      *                                      independently as itself.
  993.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  994.      */
  995.     public int rmd(final String pathname) throws IOException {
  996.         return sendCommand(FTPCmd.RMD, pathname);
  997.     }

  998.     /**
  999.      * A convenience method to send the FTP RNFR command to the server, receive the reply, and return the reply code.
  1000.      *
  1001.      * @param pathname The pathname to rename from.
  1002.      * @return The reply code received from the server.
  1003.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1004.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1005.      *                                      independently as itself.
  1006.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1007.      */
  1008.     public int rnfr(final String pathname) throws IOException {
  1009.         return sendCommand(FTPCmd.RNFR, pathname);
  1010.     }

  1011.     /**
  1012.      * A convenience method to send the FTP RNTO command to the server, receive the reply, and return the reply code.
  1013.      *
  1014.      * @param pathname The pathname to rename to
  1015.      * @return The reply code received from the server.
  1016.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1017.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1018.      *                                      independently as itself.
  1019.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1020.      */
  1021.     public int rnto(final String pathname) throws IOException {
  1022.         return sendCommand(FTPCmd.RNTO, pathname);
  1023.     }

  1024.     private void send(final String message) throws IOException, FTPConnectionClosedException, SocketException {
  1025.         try {
  1026.             _controlOutput_.write(message);
  1027.             _controlOutput_.flush();
  1028.         } catch (final SocketException e) {
  1029.             if (!isConnected()) {
  1030.                 throw new FTPConnectionClosedException("Connection unexpectedly closed.");
  1031.             }
  1032.             throw e;
  1033.         }
  1034.     }

  1035.     /**
  1036.      * Sends an FTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
  1037.      * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
  1038.      *
  1039.      * @param command The FTPCmd enum corresponding to the FTP command to send.
  1040.      * @return The integer value of the FTP reply code returned by the server in response to the command.
  1041.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1042.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1043.      *                                      independently as itself.
  1044.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1045.      * @since 3.3
  1046.      */
  1047.     public int sendCommand(final FTPCmd command) throws IOException {
  1048.         return sendCommand(command, null);
  1049.     }

  1050.     /**
  1051.      * Sends an FTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
  1052.      * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
  1053.      *
  1054.      * @param command The FTPCmd enum corresponding to the FTP command to send.
  1055.      * @param args    The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
  1056.      * @return The integer value of the FTP reply code returned by the server in response to the command.
  1057.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1058.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1059.      *                                      independently as itself.
  1060.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1061.      * @since 3.3
  1062.      */
  1063.     public int sendCommand(final FTPCmd command, final String args) throws IOException {
  1064.         return sendCommand(command.getCommand(), args);
  1065.     }

  1066.     /**
  1067.      * 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
  1068.      * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
  1069.      *
  1070.      * @param command The FTPCommand constant corresponding to the FTP command to send.
  1071.      * @return The integer value of the FTP reply code returned by the server in response to the command.
  1072.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1073.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1074.      *                                      independently as itself.
  1075.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1076.      */
  1077.     public int sendCommand(final int command) throws IOException {
  1078.         return sendCommand(command, null);
  1079.     }

  1080.     /**
  1081.      * Sends an FTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
  1082.      * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
  1083.      *
  1084.      * @param command The FTPCommand constant corresponding to the FTP command to send.
  1085.      * @param args    The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
  1086.      * @return The integer value of the FTP reply code returned by the server in response to the command.
  1087.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1088.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1089.      *                                      independently as itself.
  1090.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1091.      * @deprecated (3.3) Use {@link #sendCommand(FTPCmd, String)} instead
  1092.      */
  1093.     @Deprecated
  1094.     public int sendCommand(final int command, final String args) throws IOException {
  1095.         return sendCommand(FTPCommand.getCommand(command), args);
  1096.     }

  1097.     /**
  1098.      * 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
  1099.      * information, the actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
  1100.      *
  1101.      * @param command The text representation of the FTP command to send.
  1102.      * @return The integer value of the FTP reply code returned by the server in response to the command.
  1103.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1104.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1105.      *                                      independently as itself.
  1106.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1107.      */
  1108.     public int sendCommand(final String command) throws IOException {
  1109.         return sendCommand(command, null);
  1110.     }

  1111.     /**
  1112.      * Sends an FTP command to the server, waits for a reply and returns the numerical response code. After invocation, for more detailed information, the
  1113.      * actual reply text can be accessed by calling {@link #getReplyString getReplyString } or {@link #getReplyStrings getReplyStrings }.
  1114.      *
  1115.      * @param command The text representation of the FTP command to send.
  1116.      * @param args    The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
  1117.      * @return The integer value of the FTP reply code returned by the server in response to the command.
  1118.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1119.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1120.      *                                      independently as itself.
  1121.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1122.      */
  1123.     public int sendCommand(final String command, final String args) throws IOException {
  1124.         if (_controlOutput_ == null) {
  1125.             throw new IOException("Connection is not open");
  1126.         }
  1127.         final String message = buildMessage(command, args);
  1128.         send(message);
  1129.         fireCommandSent(command, message);
  1130.         return getReply();
  1131.     }

  1132.     /**
  1133.      * Saves the character encoding to be used by the FTP control connection. Some FTP servers require that commands be issued in a non-ASCII encoding like
  1134.      * UTF-8 so that file names with multi-byte character representations (e.g, Big 8) can be specified.
  1135.      * <p>
  1136.      * Please note that this has to be set before the connection is established.
  1137.      *
  1138.      * @param encoding The new character encoding for the control connection.
  1139.      */
  1140.     public void setControlEncoding(final String encoding) {
  1141.         _controlEncoding = encoding;
  1142.     }

  1143.     /**
  1144.      * Sets strict multiline parsing.
  1145.      *
  1146.      * @param strictMultilineParsing the setting
  1147.      * @since 2.0
  1148.      */
  1149.     public void setStrictMultilineParsing(final boolean strictMultilineParsing) {
  1150.         this.strictMultilineParsing = strictMultilineParsing;
  1151.     }

  1152.     /**
  1153.      * Sets strict non-multiline parsing.
  1154.      * <p>
  1155.      * If true, it requires the 3-digit code be followed by space and some text. <br>
  1156.      * If false, only the 3-digit code is required (as was the case for versions up to 3.5)
  1157.      * <p>
  1158.      * <b>This should not be required by a well-behaved FTP server</b> <br>
  1159.      *
  1160.      * @param strictReplyParsing the setting
  1161.      * @since 3.6
  1162.      */
  1163.     public void setStrictReplyParsing(final boolean strictReplyParsing) {
  1164.         this.strictReplyParsing = strictReplyParsing;
  1165.     }

  1166.     /**
  1167.      * A convenience method to send the FTP SITE command to the server, receive the reply, and return the reply code.
  1168.      *
  1169.      * @param parameters The site parameters to send.
  1170.      * @return The reply code received from the server.
  1171.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1172.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1173.      *                                      independently as itself.
  1174.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1175.      */
  1176.     public int site(final String parameters) throws IOException {
  1177.         return sendCommand(FTPCmd.SITE, parameters);
  1178.     }

  1179.     /**
  1180.      * A convenience method to send the FTP SIZE command to the server, receive the reply, and return the reply code.
  1181.      *
  1182.      * @param parameters The site parameters to send.
  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.      * @since 3.7
  1189.      */
  1190.     public int size(final String parameters) throws IOException {
  1191.         return sendCommand(FTPCmd.SIZE, parameters);
  1192.     }

  1193.     /**
  1194.      * A convenience method to send the FTP SMNT command to the server, receive the reply, and return the reply code.
  1195.      *
  1196.      * @param dir The directory name.
  1197.      * @return The reply code received from the server.
  1198.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1199.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1200.      *                                      independently as itself.
  1201.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1202.      */
  1203.     public int smnt(final String dir) throws IOException {
  1204.         return sendCommand(FTPCmd.SMNT, dir);
  1205.     }

  1206.     /**
  1207.      * A convenience method to send the FTP STAT command to the server, receive the reply, and return the reply code.
  1208.      *
  1209.      * @return The reply code received from the server.
  1210.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1211.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1212.      *                                      independently as itself.
  1213.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1214.      */
  1215.     public int stat() throws IOException {
  1216.         return sendCommand(FTPCmd.STAT);
  1217.     }

  1218.     /**
  1219.      * A convenience method to send the FTP STAT command to the server, receive the reply, and return the reply code.
  1220.      *
  1221.      * @param pathname A pathname to list.
  1222.      * @return The reply code received from the server.
  1223.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1224.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1225.      *                                      independently as itself.
  1226.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1227.      */
  1228.     public int stat(final String pathname) throws IOException {
  1229.         return sendCommand(FTPCmd.STAT, pathname);
  1230.     }

  1231.     /**
  1232.      * A convenience method to send the FTP STOR command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  1233.      * 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
  1234.      * for you.
  1235.      *
  1236.      * @param pathname The pathname to use for the file when stored at the remote end of the transfer.
  1237.      * @return The reply code received from the server.
  1238.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1239.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1240.      *                                      independently as itself.
  1241.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1242.      */
  1243.     public int stor(final String pathname) throws IOException {
  1244.         return sendCommand(FTPCmd.STOR, pathname);
  1245.     }

  1246.     /**
  1247.      * A convenience method to send the FTP STOU command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  1248.      * 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
  1249.      * for you.
  1250.      *
  1251.      * @return The reply code received from the server.
  1252.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1253.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1254.      *                                      independently as itself.
  1255.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1256.      */
  1257.     public int stou() throws IOException {
  1258.         return sendCommand(FTPCmd.STOU);
  1259.     }

  1260.     /**
  1261.      * A convenience method to send the FTP STOU command to the server, receive the reply, and return the reply code. Remember, it is up to you to manage the
  1262.      * 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
  1263.      * for you.
  1264.      *
  1265.      * @param pathname The base pathname to use for the file when stored at the remote end of the transfer. Some FTP servers require this.
  1266.      * @return The reply code received from the server.
  1267.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1268.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1269.      *                                      independently as itself.
  1270.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1271.      */
  1272.     public int stou(final String pathname) throws IOException {
  1273.         return sendCommand(FTPCmd.STOU, pathname);
  1274.     }

  1275.     // The RFC-compliant multiline termination check
  1276.     private boolean strictCheck(final String line, final String code) {
  1277.         return !(line.startsWith(code) && line.charAt(REPLY_CODE_LEN) == ' ');
  1278.     }

  1279.     /**
  1280.      * A convenience method to send the FTP STRU command to the server, receive the reply, and return the reply code.
  1281.      *
  1282.      * @param structure The structure of the file (one of the <code>_STRUCTURE</code> constants).
  1283.      * @return The reply code received from the server.
  1284.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1285.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1286.      *                                      independently as itself.
  1287.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1288.      */
  1289.     public int stru(final int structure) throws IOException {
  1290.         return sendCommand(FTPCmd.STRU, modeStringAt(structure));
  1291.     }

  1292.     /**
  1293.      * A convenience method to send the FTP SYST command to the server, receive the reply, and return the reply code.
  1294.      *
  1295.      * @return The reply code received from the server.
  1296.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1297.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1298.      *                                      independently as itself.
  1299.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1300.      */
  1301.     public int syst() throws IOException {
  1302.         return sendCommand(FTPCmd.SYST);
  1303.     }

  1304.     /**
  1305.      * A convenience method to send the FTP TYPE command to the server, receive the reply, and return the reply code.
  1306.      *
  1307.      * @param fileType The type of the file (one of the <code>FILE_TYPE</code> constants).
  1308.      * @return The reply code received from the server.
  1309.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1310.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1311.      *                                      independently as itself.
  1312.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1313.      */
  1314.     public int type(final int fileType) throws IOException {
  1315.         return sendCommand(FTPCmd.TYPE, modeStringAt(fileType));
  1316.     }

  1317.     /**
  1318.      * A convenience method to send the FTP TYPE command for text files to the server, receive the reply, and return the reply code.
  1319.      *
  1320.      * @param fileType         The type of the file (one of the <code>FILE_TYPE</code> constants).
  1321.      * @param formatOrByteSize The format of the file (one of the <code>_FORMAT</code> constants). In the case of <code>LOCAL_FILE_TYPE</code>, the byte size.
  1322.      * @return The reply code received from the server.
  1323.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1324.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1325.      *                                      independently as itself.
  1326.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1327.      */
  1328.     public int type(final int fileType, final int formatOrByteSize) throws IOException {
  1329.         final StringBuilder arg = new StringBuilder();
  1330.         arg.append(modeCharAt(fileType));
  1331.         arg.append(' ');
  1332.         if (fileType == LOCAL_FILE_TYPE) {
  1333.             arg.append(formatOrByteSize);
  1334.         } else {
  1335.             arg.append(modeCharAt(formatOrByteSize));
  1336.         }

  1337.         return sendCommand(FTPCmd.TYPE, arg.toString());
  1338.     }

  1339.     /**
  1340.      * A convenience method to send the FTP USER command to the server, receive the reply, and return the reply code.
  1341.      *
  1342.      * @param user The user to login under.
  1343.      * @return The reply code received from the server.
  1344.      * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a result of the client being idle or some other reason
  1345.      *                                      causing the server to send FTP reply code 421. This exception may be caught either as an IOException or
  1346.      *                                      independently as itself.
  1347.      * @throws IOException                  If an I/O error occurs while either sending the command or receiving the server reply.
  1348.      */
  1349.     public int user(final String user) throws IOException {
  1350.         return sendCommand(FTPCmd.USER, user);
  1351.     }
  1352. }