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