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