001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.net.ftp;
018
019import java.io.BufferedInputStream;
020import java.io.BufferedOutputStream;
021import java.io.BufferedReader;
022import java.io.BufferedWriter;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.InputStreamReader;
026import java.io.OutputStream;
027import java.io.OutputStreamWriter;
028import java.io.Reader;
029import java.net.Inet6Address;
030import java.net.InetAddress;
031import java.net.InetSocketAddress;
032import java.net.ServerSocket;
033import java.net.Socket;
034import java.net.SocketException;
035import java.net.SocketTimeoutException;
036import java.net.UnknownHostException;
037import java.util.ArrayList;
038import java.util.Calendar;
039import java.util.HashMap;
040import java.util.HashSet;
041import java.util.Locale;
042import java.util.Properties;
043import java.util.Random;
044import java.util.Set;
045import java.util.regex.Matcher;
046
047import org.apache.commons.net.MalformedServerReplyException;
048import org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory;
049import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory;
050import org.apache.commons.net.ftp.parser.MLSxEntryParser;
051import org.apache.commons.net.io.CRLFLineReader;
052import org.apache.commons.net.io.CopyStreamAdapter;
053import org.apache.commons.net.io.CopyStreamEvent;
054import org.apache.commons.net.io.CopyStreamListener;
055import org.apache.commons.net.io.FromNetASCIIInputStream;
056import org.apache.commons.net.io.SocketOutputStream;
057import org.apache.commons.net.io.ToNetASCIIOutputStream;
058import org.apache.commons.net.io.Util;
059import org.apache.commons.net.util.NetConstants;
060
061/**
062 * FTPClient encapsulates all the functionality necessary to store and
063 * retrieve files from an FTP server.  This class takes care of all
064 * low level details of interacting with an FTP server and provides
065 * a convenient higher level interface.  As with all classes derived
066 * from {@link org.apache.commons.net.SocketClient},
067 * you must first connect to the server with
068 * {@link org.apache.commons.net.SocketClient#connect  connect }
069 * before doing anything, and finally
070 * {@link org.apache.commons.net.SocketClient#disconnect  disconnect }
071 * after you're completely finished interacting with the server.
072 * Then you need to check the FTP reply code to see if the connection
073 * was successful.  For example:
074 * <pre>
075 *    FTPClient ftp = new FTPClient();
076 *    FTPClientConfig config = new FTPClientConfig();
077 *    config.setXXX(YYY); // change required options
078 *    // for example config.setServerTimeZoneId("Pacific/Pitcairn")
079 *    ftp.configure(config );
080 *    boolean error = false;
081 *    try {
082 *      int reply;
083 *      String server = "ftp.example.com";
084 *      ftp.connect(server);
085 *      System.out.println("Connected to " + server + ".");
086 *      System.out.print(ftp.getReplyString());
087 *
088 *      // After connection attempt, you should check the reply code to verify
089 *      // success.
090 *      reply = ftp.getReplyCode();
091 *
092 *      if(!FTPReply.isPositiveCompletion(reply)) {
093 *        ftp.disconnect();
094 *        System.err.println("FTP server refused connection.");
095 *        System.exit(1);
096 *      }
097 *      ... // transfer files
098 *      ftp.logout();
099 *    } catch(IOException e) {
100 *      error = true;
101 *      e.printStackTrace();
102 *    } finally {
103 *      if(ftp.isConnected()) {
104 *        try {
105 *          ftp.disconnect();
106 *        } catch(IOException ioe) {
107 *          // do nothing
108 *        }
109 *      }
110 *      System.exit(error ? 1 : 0);
111 *    }
112 * </pre>
113 * <p>
114 * Immediately after connecting is the only real time you need to check the
115 * reply code (because connect is of type void).  The convention for all the
116 * FTP command methods in FTPClient is such that they either return a
117 * boolean value or some other value.
118 * The boolean methods return true on a successful completion reply from
119 * the FTP server and false on a reply resulting in an error condition or
120 * failure.  The methods returning a value other than boolean return a value
121 * containing the higher level data produced by the FTP command, or null if a
122 * reply resulted in an error condition or failure.  If you want to access
123 * the exact FTP reply code causing a success or failure, you must call
124 * {@link org.apache.commons.net.ftp.FTP#getReplyCode  getReplyCode } after
125 * a success or failure.
126 * <p>
127 * The default settings for FTPClient are for it to use
128 * <code> FTP.ASCII_FILE_TYPE </code>,
129 * <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
130 * <code> FTP.STREAM_TRANSFER_MODE </code>, and
131 * <code> FTP.FILE_STRUCTURE </code>.  The only file types directly supported
132 * are <code> FTP.ASCII_FILE_TYPE </code> and
133 * <code> FTP.BINARY_FILE_TYPE </code>.  Because there are at least 4
134 * different EBCDIC encodings, we have opted not to provide direct support
135 * for EBCDIC.  To transfer EBCDIC and other unsupported file types you
136 * must create your own filter InputStreams and OutputStreams and wrap
137 * them around the streams returned or required by the FTPClient methods.
138 * FTPClient uses the {@link ToNetASCIIOutputStream NetASCII}
139 * filter streams to provide transparent handling of ASCII files.  We will
140 * consider incorporating EBCDIC support if there is enough demand.
141 * <p>
142 * <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
143 * <code> FTP.STREAM_TRANSFER_MODE </code>, and
144 * <code> FTP.FILE_STRUCTURE </code> are the only supported formats,
145 * transfer modes, and file structures.
146 * <p>
147 * Because the handling of sockets on different platforms can differ
148 * significantly, the FTPClient automatically issues a new PORT (or EPRT) command
149 * prior to every transfer requiring that the server connect to the client's
150 * data port.  This ensures identical problem-free behavior on Windows, Unix,
151 * and Macintosh platforms.  Additionally, it relieves programmers from
152 * having to issue the PORT (or EPRT) command themselves and dealing with platform
153 * dependent issues.
154 * <p>
155 * Additionally, for security purposes, all data connections to the
156 * client are verified to ensure that they originated from the intended
157 * party (host and port).  If a data connection is initiated by an unexpected
158 * party, the command will close the socket and throw an IOException.  You
159 * may disable this behavior with
160 * {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()}.
161 * <p>
162 * You should keep in mind that the FTP server may choose to prematurely
163 * close a connection if the client has been idle for longer than a
164 * given time period (usually 900 seconds).  The FTPClient class will detect a
165 * premature FTP server connection closing when it receives a
166 * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE }
167 *  response to a command.
168 * When that occurs, the FTP class method encountering that reply will throw
169 * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException}
170 * .
171 * <code>FTPConnectionClosedException</code>
172 * is a subclass of <code> IOException </code> and therefore need not be
173 * caught separately, but if you are going to catch it separately, its
174 * catch block must appear before the more general <code> IOException </code>
175 * catch block.  When you encounter an
176 * {@link org.apache.commons.net.ftp.FTPConnectionClosedException}
177 * , you must disconnect the connection with
178 * {@link #disconnect  disconnect() } to properly clean up the
179 * system resources used by FTPClient.  Before disconnecting, you may check the
180 * last reply code and text with
181 * {@link org.apache.commons.net.ftp.FTP#getReplyCode  getReplyCode },
182 * {@link org.apache.commons.net.ftp.FTP#getReplyString  getReplyString },
183 * and
184 * {@link org.apache.commons.net.ftp.FTP#getReplyStrings  getReplyStrings}.
185 * You may avoid server disconnections while the client is idle by
186 * periodically sending NOOP commands to the server.
187 * <p>
188 * Rather than list it separately for each method, we mention here that
189 * every method communicating with the server and throwing an IOException
190 * can also throw a
191 * {@link org.apache.commons.net.MalformedServerReplyException}
192 * , which is a subclass
193 * of IOException.  A MalformedServerReplyException will be thrown when
194 * the reply received from the server deviates enough from the protocol
195 * specification that it cannot be interpreted in a useful manner despite
196 * attempts to be as lenient as possible.
197 * <p>
198 * Listing API Examples
199 * Both paged and unpaged examples of directory listings are available,
200 * as follows:
201 * <p>
202 * Unpaged (whole list) access, using a parser accessible by auto-detect:
203 * <pre>
204 *    FTPClient f = new FTPClient();
205 *    f.connect(server);
206 *    f.login(username, password);
207 *    FTPFile[] files = f.listFiles(directory);
208 * </pre>
209 * <p>
210 * Paged access, using a parser not accessible by auto-detect.  The class
211 * defined in the first parameter of initateListParsing should be derived
212 * from org.apache.commons.net.FTPFileEntryParser:
213 * <pre>
214 *    FTPClient f = new FTPClient();
215 *    f.connect(server);
216 *    f.login(username, password);
217 *    FTPListParseEngine engine =
218 *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
219 *
220 *    while (engine.hasNext()) {
221 *       FTPFile[] files = engine.getNext(25);  // "page size" you want
222 *       //do whatever you want with these files, display them, etc.
223 *       //expensive FTPFile objects not created until needed.
224 *    }
225 * </pre>
226 * <p>
227 * Paged access, using a parser accessible by auto-detect:
228 * <pre>
229 *    FTPClient f = new FTPClient();
230 *    f.connect(server);
231 *    f.login(username, password);
232 *    FTPListParseEngine engine = f.initiateListParsing(directory);
233 *
234 *    while (engine.hasNext()) {
235 *       FTPFile[] files = engine.getNext(25);  // "page size" you want
236 *       //do whatever you want with these files, display them, etc.
237 *       //expensive FTPFile objects not created until needed.
238 *    }
239 * </pre>
240 * <p>
241 * For examples of using FTPClient on servers whose directory listings
242 * <ul>
243 * <li>use languages other than English</li>
244 * <li>use date formats other than the American English "standard" <code>MM d yyyy</code></li>
245 * <li>are in different time zones and you need accurate timestamps for dependency checking
246 *     as in Ant</li>
247 * </ul>see {@link  FTPClientConfig  FTPClientConfig}.
248 * <p>
249 * <b>Control channel keep-alive feature</b>:
250 * <p>
251 * <b>Please note:</b> this does not apply to the methods where the user is responsible for writing or reading
252 * the data stream, i.e. {@link #retrieveFileStream(String)} , {@link #storeFileStream(String)}
253 * and the other xxxFileStream methods
254 * <p>
255 * During file transfers, the data connection is busy, but the control connection is idle.
256 * FTP servers know that the control connection is in use, so won't close it through lack of activity,
257 * but it's a lot harder for network routers to know that the control and data connections are associated
258 * with each other.
259 * Some routers may treat the control connection as idle, and disconnect it if the transfer over the data
260 * connection takes longer than the allowable idle time for the router.
261 * <br>
262 * One solution to this is to send a safe command (i.e. NOOP) over the control connection to reset the router's
263 * idle timer. This is enabled as follows:
264 * <pre>
265 *     ftpClient.setControlKeepAliveTimeout(300); // set timeout to 5 minutes
266 * </pre>
267 * This will cause the file upload/download methods to send a NOOP approximately every 5 minutes.
268 * The following public methods support this:
269 * <ul>
270 * <li>{@link #retrieveFile(String, OutputStream)}</li>
271 * <li>{@link #appendFile(String, InputStream)}</li>
272 * <li>{@link #storeFile(String, InputStream)}</li>
273 * <li>{@link #storeUniqueFile(InputStream)}</li>
274 * <li>{@link #storeUniqueFileStream(String)}</li>
275 * </ul>
276 * This feature does not apply to the methods where the user is responsible for writing or reading
277 * the data stream, i.e. {@link #retrieveFileStream(String)} , {@link #storeFileStream(String)}
278 * and the other xxxFileStream methods.
279 * In such cases, the user is responsible for keeping the control connection alive if necessary.
280 * <p>
281 * The implementation currently uses a {@link CopyStreamListener} which is passed to the
282 * {@link Util#copyStream(InputStream, OutputStream, int, long, CopyStreamListener, boolean)}
283 * method, so the timing is partially dependent on how long each block transfer takes.
284 * <p>
285 * <b>This keep-alive feature is optional; if it does not help or causes problems then don't use it.</b>
286 *
287 * @see #FTP_SYSTEM_TYPE
288 * @see #SYSTEM_TYPE_PROPERTIES
289 * @see FTP
290 * @see FTPConnectionClosedException
291 * @see FTPFileEntryParser
292 * @see FTPFileEntryParserFactory
293 * @see DefaultFTPFileEntryParserFactory
294 * @see FTPClientConfig
295 *
296 * @see org.apache.commons.net.MalformedServerReplyException
297 */
298public class FTPClient extends FTP implements Configurable {
299    // @since 3.0
300    private static class CSL implements CopyStreamListener {
301
302        private final FTPClient parent;
303        private final long idleMillis;
304        private final int currentSoTimeoutMillis;
305
306        private long timeMillis = System.currentTimeMillis();
307        private int notAcked;
308        private int acksAcked;
309        private int ioErrors;
310
311        CSL(final FTPClient parent, final long idleTimeMillis, final int maxWaitMillis) throws SocketException {
312            this.idleMillis = idleTimeMillis;
313            this.parent = parent;
314            this.currentSoTimeoutMillis = parent.getSoTimeout();
315            parent.setSoTimeout(maxWaitMillis);
316        }
317
318        @Override
319        public void bytesTransferred(final CopyStreamEvent event) {
320            bytesTransferred(event.getTotalBytesTransferred(), event.getBytesTransferred(), event.getStreamSize());
321        }
322
323        @Override
324        public void bytesTransferred(final long totalBytesTransferred,
325                final int bytesTransferred, final long streamSize) {
326            final long nowMillis = System.currentTimeMillis();
327            if (nowMillis - timeMillis > idleMillis) {
328                try {
329                    parent.__noop();
330                    acksAcked++;
331                } catch (final SocketTimeoutException e) {
332                    notAcked++;
333                } catch (final IOException e) {
334                    ioErrors++;
335                    // Ignored
336                }
337                timeMillis = nowMillis;
338            }
339        }
340
341        int[] cleanUp() throws IOException {
342            final int remain = notAcked;
343            try {
344                while(notAcked > 0) {
345                    parent.getReply(); // we do want to see these
346                    notAcked--; // only decrement if actually received
347                }
348            } catch (final SocketTimeoutException e) { // NET-584
349                // ignored
350            } finally {
351                parent.setSoTimeout(currentSoTimeoutMillis);
352            }
353            return new int [] {acksAcked, remain, notAcked, ioErrors}; // debug counts
354        }
355
356    }
357
358    /**
359     * Strategy interface for updating host names received from FTP server
360     * for passive NAT workaround.
361     *
362     * @since 3.6
363     */
364    public interface HostnameResolver {
365        String resolve(String hostname) throws UnknownHostException;
366    }
367
368    /**
369     * Default strategy for passive NAT workaround (site-local
370     * replies are replaced.)
371     * @since 3.6
372     */
373    public static class NatServerResolverImpl implements HostnameResolver {
374        private final FTPClient client;
375
376        public NatServerResolverImpl(final FTPClient client) {
377            this.client = client;
378        }
379
380        @Override
381        public String resolve(final String hostname) throws UnknownHostException {
382            String newHostname = hostname;
383            final InetAddress host = InetAddress.getByName(newHostname);
384            // reply is a local address, but target is not - assume NAT box changed the PASV reply
385            if (host.isSiteLocalAddress()) {
386                final InetAddress remote = this.client.getRemoteAddress();
387                if (!remote.isSiteLocalAddress()){
388                    newHostname = remote.getHostAddress();
389                }
390            }
391            return newHostname;
392        }
393    }
394
395    private static class PropertiesSingleton {
396
397        static final Properties PROPERTIES;
398
399        static {
400            final InputStream resourceAsStream = FTPClient.class.getResourceAsStream(SYSTEM_TYPE_PROPERTIES);
401            Properties p = null;
402            if (resourceAsStream != null) {
403                p = new Properties();
404                try {
405                    p.load(resourceAsStream);
406                } catch (final IOException e) {
407                    // Ignored
408                } finally {
409                    try {
410                        resourceAsStream.close();
411                    } catch (final IOException e) {
412                        // Ignored
413                    }
414                }
415            }
416            PROPERTIES = p;
417        }
418
419    }
420
421    /**
422     * The system property ({@value}) which can be used to override the system type.<br>
423     * If defined, the value will be used to create any automatically created parsers.
424     *
425     * @since 3.0
426     */
427    public static final String FTP_SYSTEM_TYPE = "org.apache.commons.net.ftp.systemType";
428
429    /**
430     * The system property ({@value}) which can be used as the default system type.<br>
431     * If defined, the value will be used if the SYST command fails.
432     *
433     * @since 3.1
434     */
435    public static final String FTP_SYSTEM_TYPE_DEFAULT = "org.apache.commons.net.ftp.systemType.default";
436
437    /**
438     * The name of an optional systemType properties file ({@value}), which is loaded
439     * using {@link Class#getResourceAsStream(String)}.<br>
440     * The entries are the systemType (as determined by {@link FTPClient#getSystemType})
441     * and the values are the replacement type or parserClass, which is passed to
442     * {@link FTPFileEntryParserFactory#createFileEntryParser(String)}.<br>
443     * For example:
444     * <pre>
445     * Plan 9=Unix
446     * OS410=org.apache.commons.net.ftp.parser.OS400FTPEntryParser
447     * </pre>
448     *
449     * @since 3.0
450     */
451    public static final String SYSTEM_TYPE_PROPERTIES = "/systemType.properties";
452
453    /**
454     * A constant indicating the FTP session is expecting all transfers
455     * to occur between the client (local) and server and that the server
456     * should connect to the client's data port to initiate a data transfer.
457     * This is the default data connection mode when and FTPClient instance
458     * is created.
459     */
460    public static final int ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0;
461
462    /**
463     * A constant indicating the FTP session is expecting all transfers
464     * to occur between two remote servers and that the server
465     * the client is connected to should connect to the other server's
466     * data port to initiate a data transfer.
467     */
468    public static final int ACTIVE_REMOTE_DATA_CONNECTION_MODE = 1;
469
470    /**
471     * A constant indicating the FTP session is expecting all transfers
472     * to occur between the client (local) and server and that the server
473     * is in passive mode, requiring the client to connect to the
474     * server's data port to initiate a transfer.
475     */
476    public static final int PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2;
477
478    /**
479     * A constant indicating the FTP session is expecting all transfers
480     * to occur between two remote servers and that the server
481     * the client is connected to is in passive mode, requiring the other
482     * server to connect to the first server's data port to initiate a data
483     * transfer.
484     */
485    public static final int PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3;
486
487    /** Pattern for PASV mode responses. Groups: (n,n,n,n),(n),(n) */
488    private static final java.util.regex.Pattern PARMS_PAT;
489
490    static {
491        PARMS_PAT = java.util.regex.Pattern.compile(
492                "(\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}),(\\d{1,3}),(\\d{1,3})");
493    }
494
495    private static Properties getOverrideProperties() {
496        return PropertiesSingleton.PROPERTIES;
497    }
498
499    /**
500     * Parse the pathname from a CWD reply.
501     * <p>
502     * According to RFC959 (http://www.ietf.org/rfc/rfc959.txt),
503     * it should be the same as for MKD i.e.
504     * {@code 257<space>"<directory-name>"[<space>commentary]}
505     * where any double-quotes in {@code <directory-name>} are doubled.
506     * Unlike MKD, the commentary is optional.
507     * <p>
508     * However, see NET-442 for an exception.
509     *
510     * @param reply
511     * @return the pathname, without enclosing quotes,
512     * or the full string after the reply code and space if the syntax is invalid
513     * (i.e. enclosing quotes are missing or embedded quotes are not doubled)
514     */
515    // package protected for access by test cases
516    static String parsePathname(final String reply)
517    {
518        final String param = reply.substring(REPLY_CODE_LEN + 1);
519        if (param.startsWith("\"")) {
520            final StringBuilder sb = new StringBuilder();
521            boolean quoteSeen = false;
522            // start after initial quote
523            for(int i=1; i < param.length(); i++) {
524                final char ch = param.charAt(i);
525                if (ch=='"') {
526                    if (quoteSeen) {
527                        sb.append(ch);
528                        quoteSeen=false;
529                    } else {
530                        // don't output yet, in case doubled
531                        quoteSeen=true;
532                    }
533                } else {
534                    if (quoteSeen) { // found lone trailing quote within string
535                        return sb.toString();
536                    }
537                    sb.append(ch); // just another character
538                }
539            }
540            if (quoteSeen) { // found lone trailing quote at end of string
541                return sb.toString();
542            }
543        }
544        // malformed reply, return all after reply code and space
545        return param;
546    }
547
548    private int dataConnectionMode;
549    private int dataTimeoutMillis;
550
551    private int passivePort;
552    private String passiveHost;
553    private final Random random;
554    private int activeMinPort;
555    private int activeMaxPort;
556    private InetAddress activeExternalHost;
557
558    /** overrides __activeExternalHost in EPRT/PORT commands. */
559    private InetAddress reportActiveExternalHost;
560
561    /** The address to bind to on passive connections, if necessary. */
562    private InetAddress passiveLocalHost;
563    private int fileType;
564    @SuppressWarnings("unused") // fields are written, but currently not read
565    private int fileFormat;
566    @SuppressWarnings("unused") // field is written, but currently not read
567    private int fileStructure;
568    @SuppressWarnings("unused") // field is written, but currently not read
569    private int fileTransferMode;
570
571    private boolean remoteVerificationEnabled;
572
573    private long restartOffset;
574
575    private FTPFileEntryParserFactory parserFactory;
576
577    private int bufferSize; // buffersize for buffered data streams
578
579    private int sendDataSocketBufferSize;
580
581    private int receiveDataSocketBufferSize;
582
583    private boolean listHiddenFiles;
584
585    private boolean useEPSVwithIPv4; // whether to attempt EPSV with an IPv4 connection
586
587    // __systemName is a cached value that should not be referenced directly
588    // except when assigned in getSystemName and __initDefaults.
589    private String systemName;
590
591    // __entryParser is a cached value that should not be referenced directly
592    // except when assigned in listFiles(String, String) and __initDefaults.
593    private FTPFileEntryParser entryParser;
594
595    // Key used to create the parser; necessary to ensure that the parser type is not ignored
596    private String entryParserKey;
597
598    private FTPClientConfig configuration;
599
600    // Listener used by store/retrieve methods to handle keepalive
601    private CopyStreamListener copyStreamListener;
602
603    // How long to wait before sending another control keep-alive message
604    private long controlKeepAliveTimeoutMillis;
605    // How long to wait (millis) for keepalive message replies before continuing
606    // Most FTP servers don't seem to support concurrent control and data connection usage
607    private int controlKeepAliveReplyTimeoutMillis = 1000;
608
609    // Debug counts for NOOP acks
610    private int[] cslDebug;
611
612
613    /**
614     * Enable or disable replacement of internal IP in passive mode. Default enabled
615     * using {code NatServerResolverImpl}.
616     */
617    private HostnameResolver passiveNatWorkaroundStrategy = new NatServerResolverImpl(this);
618
619    /** Controls the automatic server encoding detection (only UTF-8 supported). */
620    private boolean autodetectEncoding = false;
621
622    /** Map of FEAT responses. If null, has not been initialized. */
623    private HashMap<String, Set<String>> featuresMap;
624
625    /**
626     * Default FTPClient constructor.  Creates a new FTPClient instance
627     * with the data connection mode set to
628     * <code> ACTIVE_LOCAL_DATA_CONNECTION_MODE </code>, the file type
629     * set to <code> FTP.ASCII_FILE_TYPE </code>, the
630     * file format set to <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
631     * the file structure set to <code> FTP.FILE_STRUCTURE </code>, and
632     * the transfer mode set to <code> FTP.STREAM_TRANSFER_MODE </code>.
633     * <p>
634     * The list parsing auto-detect feature can be configured to use lenient future
635     * dates (short dates may be up to one day in the future) as follows:
636     * <pre>
637     * FTPClient ftp = new FTPClient();
638     * FTPClientConfig config = new FTPClientConfig();
639     * config.setLenientFutureDates(true);
640     * ftp.configure(config );
641     * </pre>
642     */
643    public FTPClient()
644    {
645        initDefaults();
646        dataTimeoutMillis = -1;
647        remoteVerificationEnabled = true;
648        parserFactory = new DefaultFTPFileEntryParserFactory();
649        configuration      = null;
650        listHiddenFiles = false;
651        useEPSVwithIPv4 = false;
652        random = new Random();
653        passiveLocalHost   = null;
654    }
655
656    @Override
657    protected void _connectAction_() throws IOException {
658        _connectAction_(null);
659    }
660
661    /**
662     * @param socketIsReader the reader to reuse (if non-null)
663     * @throws IOException on error
664     * @since 3.4
665     */
666    @Override
667    protected void _connectAction_(final Reader socketIsReader) throws IOException {
668        super._connectAction_(socketIsReader); // sets up _input_ and _output_
669        initDefaults();
670        // must be after super._connectAction_(), because otherwise we get an
671        // Exception claiming we're not connected
672        if (autodetectEncoding) {
673            final ArrayList<String> oldReplyLines = new ArrayList<>(_replyLines);
674            final int oldReplyCode = _replyCode;
675            if (hasFeature("UTF8") || hasFeature("UTF-8")) // UTF8 appears to be the default
676            {
677                setControlEncoding("UTF-8");
678                _controlInput_ = new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding()));
679                _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding()));
680            }
681            // restore the original reply (server greeting)
682            _replyLines.clear();
683            _replyLines.addAll(oldReplyLines);
684            _replyCode = oldReplyCode;
685            _newReplyString = true;
686        }
687    }
688
689    /**
690     * Establishes a data connection with the FTP server, returning
691     * a Socket for the connection if successful.  If a restart
692     * offset has been set with {@link #setRestartOffset(long)},
693     * a REST command is issued to the server with the offset as
694     * an argument before establishing the data connection.  Active
695     * mode connections also cause a local PORT command to be issued.
696     *
697     * @param command  The int representation of the FTP command to send.
698     * @param arg The arguments to the FTP command.  If this parameter is
699     *             set to null, then the command is sent with no argument.
700     * @return A Socket corresponding to the established data connection.
701     *         Null is returned if an FTP protocol error is reported at
702     *         any point during the establishment and initialization of
703     *         the connection.
704     * @throws IOException  If an I/O error occurs while either sending a
705     *      command to the server or receiving a reply from the server.
706     * @since 3.3
707     */
708    protected Socket _openDataConnection_(final FTPCmd command, final String arg)
709    throws IOException
710    {
711        return _openDataConnection_(command.getCommand(), arg);
712    }
713
714    /**
715     * Establishes a data connection with the FTP server, returning
716     * a Socket for the connection if successful.  If a restart
717     * offset has been set with {@link #setRestartOffset(long)},
718     * a REST command is issued to the server with the offset as
719     * an argument before establishing the data connection.  Active
720     * mode connections also cause a local PORT command to be issued.
721     *
722     * @param command  The int representation of the FTP command to send.
723     * @param arg The arguments to the FTP command.  If this parameter is
724     *             set to null, then the command is sent with no argument.
725     * @return A Socket corresponding to the established data connection.
726     *         Null is returned if an FTP protocol error is reported at
727     *         any point during the establishment and initialization of
728     *         the connection.
729     * @throws IOException  If an I/O error occurs while either sending a
730     *      command to the server or receiving a reply from the server.
731     * @deprecated (3.3) Use {@link #_openDataConnection_(FTPCmd, String)} instead
732     */
733    @Deprecated
734    protected Socket _openDataConnection_(final int command, final String arg) throws IOException {
735        return _openDataConnection_(FTPCommand.getCommand(command), arg);
736    }
737
738    /**
739     * Establishes a data connection with the FTP server, returning
740     * a Socket for the connection if successful.  If a restart
741     * offset has been set with {@link #setRestartOffset(long)},
742     * a REST command is issued to the server with the offset as
743     * an argument before establishing the data connection.  Active
744     * mode connections also cause a local PORT command to be issued.
745     *
746     * @param command  The text representation of the FTP command to send.
747     * @param arg The arguments to the FTP command.  If this parameter is
748     *             set to null, then the command is sent with no argument.
749     * @return A Socket corresponding to the established data connection.
750     *         Null is returned if an FTP protocol error is reported at
751     *         any point during the establishment and initialization of
752     *         the connection.
753     * @throws IOException  If an I/O error occurs while either sending a
754     *      command to the server or receiving a reply from the server.
755     * @since 3.1
756     */
757    protected Socket _openDataConnection_(final String command, final String arg)
758    throws IOException
759    {
760        if (dataConnectionMode != ACTIVE_LOCAL_DATA_CONNECTION_MODE &&
761                dataConnectionMode != PASSIVE_LOCAL_DATA_CONNECTION_MODE) {
762            return null;
763        }
764
765        final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address;
766
767        final Socket socket;
768
769        if (dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE)
770        {
771            // if no activePortRange was set (correctly) -> getActivePort() = 0
772            // -> new ServerSocket(0) -> bind to any free local port
773            try (final ServerSocket server = _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress())) {
774                // Try EPRT only if remote server is over IPv6, if not use PORT,
775                // because EPRT has no advantage over PORT on IPv4.
776                // It could even have the disadvantage,
777                // that EPRT will make the data connection fail, because
778                // today's intelligent NAT Firewalls are able to
779                // substitute IP addresses in the PORT command,
780                // but might not be able to recognize the EPRT command.
781                if (isInet6Address) {
782                    if (!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(), server.getLocalPort()))) {
783                        return null;
784                    }
785                } else {
786                    if (!FTPReply.isPositiveCompletion(port(getReportHostAddress(), server.getLocalPort()))) {
787                        return null;
788                    }
789                }
790
791                if ((restartOffset > 0) && !restart(restartOffset)) {
792                    return null;
793                }
794
795                if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
796                    return null;
797                }
798
799                // For now, let's just use the data timeout value for waiting for
800                // the data connection.  It may be desirable to let this be a
801                // separately configurable value.  In any case, we really want
802                // to allow preventing the accept from blocking indefinitely.
803                if (dataTimeoutMillis >= 0) {
804                    server.setSoTimeout(dataTimeoutMillis);
805                }
806                socket = server.accept();
807
808                // Ensure the timeout is set before any commands are issued on the new socket
809                if (dataTimeoutMillis >= 0) {
810                    socket.setSoTimeout(dataTimeoutMillis);
811                }
812                if (receiveDataSocketBufferSize > 0) {
813                    socket.setReceiveBufferSize(receiveDataSocketBufferSize);
814                }
815                if (sendDataSocketBufferSize > 0) {
816                    socket.setSendBufferSize(sendDataSocketBufferSize);
817                }
818            }
819        }
820        else
821        { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE
822
823            // Try EPSV command first on IPv6 - and IPv4 if enabled.
824            // When using IPv4 with NAT it has the advantage
825            // to work with more rare configurations.
826            // E.g. if FTP server has a static PASV address (external network)
827            // and the client is coming from another internal network.
828            // In that case the data connection after PASV command would fail,
829            // while EPSV would make the client succeed by taking just the port.
830            final boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address;
831            if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE)
832            {
833                _parseExtendedPassiveModeReply(_replyLines.get(0));
834            }
835            else
836            {
837                if (isInet6Address) {
838                    return null; // Must use EPSV for IPV6
839                }
840                // If EPSV failed on IPV4, revert to PASV
841                if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) {
842                    return null;
843                }
844                _parsePassiveModeReply(_replyLines.get(0));
845            }
846
847            socket = _socketFactory_.createSocket();
848            if (receiveDataSocketBufferSize > 0) {
849                socket.setReceiveBufferSize(receiveDataSocketBufferSize);
850            }
851            if (sendDataSocketBufferSize > 0) {
852                socket.setSendBufferSize(sendDataSocketBufferSize);
853            }
854            if (passiveLocalHost != null) {
855                socket.bind(new InetSocketAddress(passiveLocalHost, 0));
856            }
857
858            // For now, let's just use the data timeout value for waiting for
859            // the data connection.  It may be desirable to let this be a
860            // separately configurable value.  In any case, we really want
861            // to allow preventing the accept from blocking indefinitely.
862            if (dataTimeoutMillis >= 0) {
863                socket.setSoTimeout(dataTimeoutMillis);
864            }
865
866            socket.connect(new InetSocketAddress(passiveHost, passivePort), connectTimeout);
867            if ((restartOffset > 0) && !restart(restartOffset))
868            {
869                socket.close();
870                return null;
871            }
872
873            if (!FTPReply.isPositivePreliminary(sendCommand(command, arg)))
874            {
875                socket.close();
876                return null;
877            }
878        }
879
880        if (remoteVerificationEnabled && !verifyRemote(socket))
881        {
882            // Grab the host before we close the socket to avoid NET-663
883            final InetAddress socketHost = socket.getInetAddress();
884
885            socket.close();
886
887            throw new IOException(
888                    "Host attempting data connection " + socketHost.getHostAddress() +
889                    " is not same as server " + getRemoteAddress().getHostAddress());
890        }
891
892        return socket;
893    }
894
895    protected void _parseExtendedPassiveModeReply(String reply) throws MalformedServerReplyException {
896        reply = reply.substring(reply.indexOf('(') + 1, reply.indexOf(')')).trim();
897
898        final char delim1 = reply.charAt(0);
899        final char delim2 = reply.charAt(1);
900        final char delim3 = reply.charAt(2);
901        final char delim4 = reply.charAt(reply.length() - 1);
902
903        if ((delim1 != delim2) || (delim2 != delim3) || (delim3 != delim4)) {
904            throw new MalformedServerReplyException(
905                "Could not parse extended passive host information.\nServer Reply: " + reply);
906        }
907
908        final int port;
909        try {
910            port = Integer.parseInt(reply.substring(3, reply.length() - 1));
911        } catch (final NumberFormatException e) {
912            throw new MalformedServerReplyException(
913                "Could not parse extended passive host information.\nServer Reply: " + reply);
914        }
915
916        // in EPSV mode, the passive host address is implicit
917        this.passiveHost = getRemoteAddress().getHostAddress();
918        this.passivePort = port;
919    }
920
921    /**
922     * @since 3.1
923     * @param reply the reply to parse
924     * @throws MalformedServerReplyException if the server reply does not match  (n,n,n,n),(n),(n)
925     */
926    protected void _parsePassiveModeReply(final String reply) throws MalformedServerReplyException {
927        final Matcher m = PARMS_PAT.matcher(reply);
928        if (!m.find()) {
929            throw new MalformedServerReplyException(
930                "Could not parse passive host information.\nServer Reply: " + reply);
931        }
932
933        this.passiveHost = "0,0,0,0".equals(m.group(1)) ? _socket_.getInetAddress().getHostAddress()
934            : m.group(1).replace(',', '.'); // Fix up to look like IP address
935
936        try {
937            final int oct1 = Integer.parseInt(m.group(2));
938            final int oct2 = Integer.parseInt(m.group(3));
939            passivePort = (oct1 << 8) | oct2;
940        } catch (final NumberFormatException e) {
941            throw new MalformedServerReplyException(
942                "Could not parse passive port information.\nServer Reply: " + reply);
943        }
944
945        if (passiveNatWorkaroundStrategy != null) {
946            try {
947                final String newPassiveHost = passiveNatWorkaroundStrategy.resolve(this.passiveHost);
948                if (!this.passiveHost.equals(newPassiveHost)) {
949                    fireReplyReceived(0,
950                        "[Replacing PASV mode reply address " + this.passiveHost + " with " + newPassiveHost + "]\n");
951                    this.passiveHost = newPassiveHost;
952                }
953            } catch (final UnknownHostException e) { // Should not happen as we are passing in an IP address
954                throw new MalformedServerReplyException(
955                    "Could not parse passive host information.\nServer Reply: " + reply);
956            }
957        }
958    }
959
960    /**
961     * @param command the command to get
962     * @param remote the remote file name
963     * @param local The local OutputStream to which to write the file.
964     * @return true if successful
965     * @throws IOException on error
966     * @since 3.1
967     */
968    protected boolean _retrieveFile(final String command, final String remote, final OutputStream local)
969    throws IOException
970    {
971        final Socket socket = _openDataConnection_(command, remote);
972
973        if (socket == null) {
974            return false;
975        }
976
977        InputStream input = null;
978        CSL csl = null;
979        try {
980            try {
981                if (fileType == ASCII_FILE_TYPE) {
982                    input = new FromNetASCIIInputStream(getBufferedInputStream(socket.getInputStream()));
983                } else {
984                    input = getBufferedInputStream(socket.getInputStream());
985                }
986
987                if (controlKeepAliveTimeoutMillis > 0) {
988                    csl = new CSL(this, controlKeepAliveTimeoutMillis, controlKeepAliveReplyTimeoutMillis);
989                }
990
991                // Treat everything else as binary for now
992                Util.copyStream(input, local, getBufferSize(), CopyStreamEvent.UNKNOWN_STREAM_SIZE, mergeListeners(csl),
993                    false);
994            } finally {
995                Util.closeQuietly(input);
996            }
997            // Get the transfer response
998            return completePendingCommand();
999        } finally {
1000            Util.closeQuietly(socket);
1001            if (csl != null) {
1002                cslDebug = csl.cleanUp(); // fetch any outstanding keepalive replies
1003            }
1004        }
1005    }
1006
1007
1008    /**
1009     * @param command the command to send
1010     * @param remote the remote file name
1011     * @return the stream from which to read the file
1012     * @throws IOException on error
1013     * @since 3.1
1014     */
1015    protected InputStream _retrieveFileStream(final String command, final String remote)
1016    throws IOException
1017    {
1018        final Socket socket = _openDataConnection_(command, remote);
1019
1020        if (socket == null) {
1021            return null;
1022        }
1023
1024        final InputStream input;
1025        if (fileType == ASCII_FILE_TYPE) {
1026            // We buffer ascii transfers because the buffering has to
1027            // be interposed between FromNetASCIIOutputSream and the underlying
1028            // socket input stream.  We don't buffer binary transfers
1029            // because we don't want to impose a buffering policy on the
1030            // programmer if possible.  Programmers can decide on their
1031            // own if they want to wrap the SocketInputStream we return
1032            // for file types other than ASCII.
1033            input = new FromNetASCIIInputStream(getBufferedInputStream(socket.getInputStream()));
1034        } else {
1035            input = socket.getInputStream();
1036        }
1037        return new org.apache.commons.net.io.SocketInputStream(socket, input);
1038    }
1039
1040
1041    /**
1042     * @since 3.1
1043     * @param command the command to send
1044     * @param remote the remote file name
1045     * @param local The local InputStream from which to read the data to
1046     *                be written/appended to the remote file.
1047     * @return true if successful
1048     * @throws IOException on error
1049     */
1050    protected boolean _storeFile(final String command, final String remote, final InputStream local)
1051    throws IOException
1052    {
1053        final Socket socket = _openDataConnection_(command, remote);
1054
1055        if (socket == null) {
1056            return false;
1057        }
1058
1059        final OutputStream output;
1060
1061        if (fileType == ASCII_FILE_TYPE) {
1062            output = new ToNetASCIIOutputStream(getBufferedOutputStream(socket.getOutputStream()));
1063        } else {
1064            output = getBufferedOutputStream(socket.getOutputStream());
1065        }
1066
1067        CSL csl = null;
1068        if (controlKeepAliveTimeoutMillis > 0) {
1069            csl = new CSL(this, controlKeepAliveTimeoutMillis, controlKeepAliveReplyTimeoutMillis);
1070        }
1071
1072        // Treat everything else as binary for now
1073        try
1074        {
1075            Util.copyStream(local, output, getBufferSize(),
1076                    CopyStreamEvent.UNKNOWN_STREAM_SIZE, mergeListeners(csl),
1077                    false);
1078            output.close(); // ensure the file is fully written
1079            socket.close(); // done writing the file
1080
1081            // Get the transfer response
1082            return completePendingCommand();
1083        }
1084        catch (final IOException e)
1085        {
1086            Util.closeQuietly(output); // ignore close errors here
1087            Util.closeQuietly(socket); // ignore close errors here
1088            throw e;
1089        } finally {
1090            if (csl != null) {
1091                cslDebug = csl.cleanUp(); // fetch any outstanding keepalive replies
1092            }
1093        }
1094    }
1095
1096    /**
1097     * @param command the command to send
1098     * @param remote the remote file name
1099     * @return the output stream to write to
1100     * @throws IOException on error
1101     * @since 3.1
1102     */
1103    protected OutputStream _storeFileStream(final String command, final String remote)
1104    throws IOException
1105    {
1106        final Socket socket = _openDataConnection_(command, remote);
1107
1108        if (socket == null) {
1109            return null;
1110        }
1111
1112        final OutputStream output;
1113        if (fileType == ASCII_FILE_TYPE) {
1114            // We buffer ascii transfers because the buffering has to
1115            // be interposed between ToNetASCIIOutputSream and the underlying
1116            // socket output stream.  We don't buffer binary transfers
1117            // because we don't want to impose a buffering policy on the
1118            // programmer if possible.  Programmers can decide on their
1119            // own if they want to wrap the SocketOutputStream we return
1120            // for file types other than ASCII.
1121            output = new ToNetASCIIOutputStream(getBufferedOutputStream(socket.getOutputStream()));
1122        } else {
1123            output = socket.getOutputStream();
1124        }
1125        return new SocketOutputStream(socket, output);
1126    }
1127
1128    /**
1129     * Abort a transfer in progress.
1130     *
1131     * @return True if successfully completed, false if not.
1132     * @throws FTPConnectionClosedException
1133     *      If the FTP server prematurely closes the connection as a result
1134     *      of the client being idle or some other reason causing the server
1135     *      to send FTP reply code 421.  This exception may be caught either
1136     *      as an IOException or independently as itself.
1137     * @throws IOException  If an I/O error occurs while either sending a
1138     *      command to the server or receiving a reply from the server.
1139     */
1140    public boolean abort() throws IOException
1141    {
1142        return FTPReply.isPositiveCompletion(abor());
1143    }
1144
1145    /**
1146     * Reserve a number of bytes on the server for the next file transfer.
1147     *
1148     * @param bytes  The number of bytes which the server should allocate.
1149     * @return True if successfully completed, false if not.
1150     * @throws FTPConnectionClosedException
1151     *      If the FTP server prematurely closes the connection as a result
1152     *      of the client being idle or some other reason causing the server
1153     *      to send FTP reply code 421.  This exception may be caught either
1154     *      as an IOException or independently as itself.
1155     * @throws IOException  If an I/O error occurs while either sending a
1156     *      command to the server or receiving a reply from the server.
1157     */
1158    public boolean allocate(final int bytes) throws IOException
1159    {
1160        return FTPReply.isPositiveCompletion(allo(bytes));
1161    }
1162
1163    /**
1164     * Reserve space on the server for the next file transfer.
1165     *
1166     * @param bytes  The number of bytes which the server should allocate.
1167     * @param recordSize  The size of a file record.
1168     * @return True if successfully completed, false if not.
1169     * @throws FTPConnectionClosedException
1170     *      If the FTP server prematurely closes the connection as a result
1171     *      of the client being idle or some other reason causing the server
1172     *      to send FTP reply code 421.  This exception may be caught either
1173     *      as an IOException or independently as itself.
1174     * @throws IOException  If an I/O error occurs while either sending a
1175     *      command to the server or receiving a reply from the server.
1176     */
1177    public boolean allocate(final int bytes, final int recordSize) throws IOException
1178    {
1179        return FTPReply.isPositiveCompletion(allo(bytes, recordSize));
1180    }
1181
1182    /**
1183     * Reserve a number of bytes on the server for the next file transfer.
1184     *
1185     * @param bytes  The number of bytes which the server should allocate.
1186     * @return True if successfully completed, false if not.
1187     * @throws FTPConnectionClosedException
1188     *      If the FTP server prematurely closes the connection as a result
1189     *      of the client being idle or some other reason causing the server
1190     *      to send FTP reply code 421.  This exception may be caught either
1191     *      as an IOException or independently as itself.
1192     * @throws IOException  If an I/O error occurs while either sending a
1193     *      command to the server or receiving a reply from the server.
1194     */
1195    public boolean allocate(final long bytes) throws IOException
1196    {
1197        return FTPReply.isPositiveCompletion(allo(bytes));
1198    }
1199
1200    /**
1201     * Reserve space on the server for the next file transfer.
1202     *
1203     * @param bytes  The number of bytes which the server should allocate.
1204     * @param recordSize  The size of a file record.
1205     * @return True if successfully completed, false if not.
1206     * @throws FTPConnectionClosedException
1207     *      If the FTP server prematurely closes the connection as a result
1208     *      of the client being idle or some other reason causing the server
1209     *      to send FTP reply code 421.  This exception may be caught either
1210     *      as an IOException or independently as itself.
1211     * @throws IOException  If an I/O error occurs while either sending a
1212     *      command to the server or receiving a reply from the server.
1213     */
1214    public boolean allocate(final long bytes, final int recordSize) throws IOException
1215    {
1216        return FTPReply.isPositiveCompletion(allo(bytes, recordSize));
1217    }
1218
1219    /**
1220     * Appends to a file on the server with the given name, taking input
1221     * from the given InputStream.  This method does NOT close the given
1222     * InputStream.  If the current file type is ASCII, line separators in
1223     * the file are transparently converted to the NETASCII format (i.e.,
1224     * you should not attempt to create a special InputStream to do this).
1225     *
1226     * @param remote  The name of the remote file.
1227     * @param local   The local InputStream from which to read the data to
1228     *                be appended to the remote file.
1229     * @return True if successfully completed, false if not.
1230     * @throws FTPConnectionClosedException
1231     *      If the FTP server prematurely closes the connection as a result
1232     *      of the client being idle or some other reason causing the server
1233     *      to send FTP reply code 421.  This exception may be caught either
1234     *      as an IOException or independently as itself.
1235     * @throws org.apache.commons.net.io.CopyStreamException
1236     *      If an I/O error occurs while actually
1237     *      transferring the file.  The CopyStreamException allows you to
1238     *      determine the number of bytes transferred and the IOException
1239     *      causing the error.  This exception may be caught either
1240     *      as an IOException or independently as itself.
1241     * @throws IOException  If an I/O error occurs while either sending a
1242     *      command to the server or receiving a reply from the server.
1243     */
1244    public boolean appendFile(final String remote, final InputStream local)
1245    throws IOException
1246    {
1247        return storeFile(FTPCmd.APPE, remote, local);
1248    }
1249
1250    /**
1251     * Returns an OutputStream through which data can be written to append
1252     * to a file on the server with the given name.  If the current file type
1253     * is ASCII, the returned OutputStream will convert line separators in
1254     * the file to the NETASCII format  (i.e., you should not attempt to
1255     * create a special OutputStream to do this).  You must close the
1256     * OutputStream when you finish writing to it.  The OutputStream itself
1257     * will take care of closing the parent data connection socket upon being
1258     * closed.
1259     * <p>
1260     * <b>To finalize the file transfer you must call
1261     * {@link #completePendingCommand  completePendingCommand } and
1262     * check its return value to verify success.</b>
1263     * If this is not done, subsequent commands may behave unexpectedly.
1264     *
1265     * @param remote  The name of the remote file.
1266     * @return An OutputStream through which the remote file can be appended.
1267     *      If the data connection cannot be opened (e.g., the file does not
1268     *      exist), null is returned (in which case you may check the reply
1269     *      code to determine the exact reason for failure).
1270     * @throws FTPConnectionClosedException
1271     *      If the FTP server prematurely closes the connection as a result
1272     *      of the client being idle or some other reason causing the server
1273     *      to send FTP reply code 421.  This exception may be caught either
1274     *      as an IOException or independently as itself.
1275     * @throws IOException  If an I/O error occurs while either sending a
1276     *      command to the server or receiving a reply from the server.
1277     */
1278    public OutputStream appendFileStream(final String remote) throws IOException
1279    {
1280        return storeFileStream(FTPCmd.APPE, remote);
1281    }
1282
1283
1284    /**
1285     * Change to the parent directory of the current working directory.
1286     *
1287     * @return True if successfully completed, false if not.
1288     * @throws FTPConnectionClosedException
1289     *      If the FTP server prematurely closes the connection as a result
1290     *      of the client being idle or some other reason causing the server
1291     *      to send FTP reply code 421.  This exception may be caught either
1292     *      as an IOException or independently as itself.
1293     * @throws IOException  If an I/O error occurs while either sending a
1294     *      command to the server or receiving a reply from the server.
1295     */
1296    public boolean changeToParentDirectory() throws IOException
1297    {
1298        return FTPReply.isPositiveCompletion(cdup());
1299    }
1300
1301
1302    /**
1303     * Change the current working directory of the FTP session.
1304     *
1305     * @param pathname  The new current working directory.
1306     * @return True if successfully completed, false if not.
1307     * @throws FTPConnectionClosedException
1308     *      If the FTP server prematurely closes the connection as a result
1309     *      of the client being idle or some other reason causing the server
1310     *      to send FTP reply code 421.  This exception may be caught either
1311     *      as an IOException or independently as itself.
1312     * @throws IOException  If an I/O error occurs while either sending a
1313     *      command to the server or receiving a reply from the server.
1314     */
1315    public boolean changeWorkingDirectory(final String pathname) throws IOException
1316    {
1317        return FTPReply.isPositiveCompletion(cwd(pathname));
1318    }
1319
1320    /**
1321     * There are a few FTPClient methods that do not complete the
1322     * entire sequence of FTP commands to complete a transaction.  These
1323     * commands require some action by the programmer after the reception
1324     * of a positive intermediate command.  After the programmer's code
1325     * completes its actions, it must call this method to receive
1326     * the completion reply from the server and verify the success of the
1327     * entire transaction.
1328     * <p>
1329     * For example,
1330     * <pre>
1331     * InputStream input;
1332     * OutputStream output;
1333     * input  = new FileInputStream("foobaz.txt");
1334     * output = ftp.storeFileStream("foobar.txt")
1335     * if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
1336     *     input.close();
1337     *     output.close();
1338     *     ftp.logout();
1339     *     ftp.disconnect();
1340     *     System.err.println("File transfer failed.");
1341     *     System.exit(1);
1342     * }
1343     * Util.copyStream(input, output);
1344     * input.close();
1345     * output.close();
1346     * // Must call completePendingCommand() to finish command.
1347     * if(!ftp.completePendingCommand()) {
1348     *     ftp.logout();
1349     *     ftp.disconnect();
1350     *     System.err.println("File transfer failed.");
1351     *     System.exit(1);
1352     * }
1353     * </pre>
1354     *
1355     * @return True if successfully completed, false if not.
1356     * @throws FTPConnectionClosedException
1357     *      If the FTP server prematurely closes the connection as a result
1358     *      of the client being idle or some other reason causing the server
1359     *      to send FTP reply code 421.  This exception may be caught either
1360     *      as an IOException or independently as itself.
1361     * @throws IOException  If an I/O error occurs while either sending a
1362     *      command to the server or receiving a reply from the server.
1363     */
1364    public boolean completePendingCommand() throws IOException
1365    {
1366        return FTPReply.isPositiveCompletion(getReply());
1367    }
1368
1369    /**
1370     * Implementation of the {@link Configurable Configurable} interface.
1371     * In the case of this class, configuring merely makes the config object available for the
1372     * factory methods that construct parsers.
1373     * @param config {@link FTPClientConfig FTPClientConfig} object used to
1374     * provide non-standard configurations to the parser.
1375     * @since 1.4
1376     */
1377    @Override
1378    public void configure(final FTPClientConfig config) {
1379        this.configuration = config;
1380    }
1381
1382    // package access for test purposes
1383    void createParser(final String parserKey) throws IOException {
1384        // We cache the value to avoid creation of a new object every
1385        // time a file listing is generated.
1386        // Note: we don't check against a null parserKey (NET-544)
1387        if(entryParser == null ||  (parserKey != null && ! entryParserKey.equals(parserKey))) {
1388            if (null != parserKey) {
1389                // if a parser key was supplied in the parameters,
1390                // use that to create the parser
1391                entryParser =
1392                    parserFactory.createFileEntryParser(parserKey);
1393                entryParserKey = parserKey;
1394
1395            } else {
1396                // if no parserKey was supplied, check for a configuration
1397                // in the params, and if it has a non-empty system type, use that.
1398                if (null != configuration && configuration.getServerSystemKey().length() > 0) {
1399                    entryParser =
1400                        parserFactory.createFileEntryParser(configuration);
1401                    entryParserKey = configuration.getServerSystemKey();
1402                } else {
1403                    // if a parserKey hasn't been supplied, and a configuration
1404                    // hasn't been supplied, and the override property is not set
1405                    // then autodetect by calling
1406                    // the SYST command and use that to choose the parser.
1407                    String systemType = System.getProperty(FTP_SYSTEM_TYPE);
1408                    if (systemType == null) {
1409                        systemType = getSystemType(); // cannot be null
1410                        final Properties override = getOverrideProperties();
1411                        if (override != null) {
1412                            final String newType = override.getProperty(systemType);
1413                            if (newType != null) {
1414                                systemType = newType;
1415                            }
1416                        }
1417                    }
1418                    if (null != configuration) { // system type must have been empty above
1419                        entryParser = parserFactory.createFileEntryParser(new FTPClientConfig(systemType, configuration));
1420                    } else {
1421                        entryParser = parserFactory.createFileEntryParser(systemType);
1422                    }
1423                    entryParserKey = systemType;
1424                }
1425            }
1426        }
1427    }
1428
1429    /**
1430     * Deletes a file on the FTP server.
1431     *
1432     * @param pathname   The pathname of the file to be deleted.
1433     * @return True if successfully completed, false if not.
1434     * @throws FTPConnectionClosedException
1435     *      If the FTP server prematurely closes the connection as a result
1436     *      of the client being idle or some other reason causing the server
1437     *      to send FTP reply code 421.  This exception may be caught either
1438     *      as an IOException or independently as itself.
1439     * @throws IOException  If an I/O error occurs while either sending a
1440     *      command to the server or receiving a reply from the server.
1441     */
1442    public boolean deleteFile(final String pathname) throws IOException
1443    {
1444        return FTPReply.isPositiveCompletion(dele(pathname));
1445    }
1446
1447    /**
1448     * Closes the connection to the FTP server and restores
1449     * connection parameters to the default values.
1450     *
1451     * @throws IOException If an error occurs while disconnecting.
1452     */
1453    @Override
1454    public void disconnect() throws IOException
1455    {
1456        super.disconnect();
1457        initDefaults();
1458    }
1459
1460    /**
1461     * Issue a command and wait for the reply.
1462     * <p>
1463     * Should only be used with commands that return replies on the
1464     * command channel - do not use for LIST, NLST, MLSD etc.
1465     *
1466     * @param command  The command to invoke
1467     * @param params  The parameters string, may be {@code null}
1468     * @return True if successfully completed, false if not, in which case
1469     * call {@link #getReplyCode()} or {@link #getReplyString()}
1470     * to get the reason.
1471     *
1472     * @throws IOException  If an I/O error occurs while either sending a
1473     *      command to the server or receiving a reply from the server.
1474     * @since 3.0
1475     */
1476    public boolean doCommand(final String command, final String params) throws IOException
1477    {
1478        return FTPReply.isPositiveCompletion(sendCommand(command, params));
1479    }
1480
1481    /**
1482     * Issue a command and wait for the reply, returning it as an array of strings.
1483     * <p>
1484     * Should only be used with commands that return replies on the
1485     * command channel - do not use for LIST, NLST, MLSD etc.
1486     *
1487     * @param command  The command to invoke
1488     * @param params  The parameters string, may be {@code null}
1489     * @return The array of replies, or {@code null} if the command failed, in which case
1490     * call {@link #getReplyCode()} or {@link #getReplyString()}
1491     * to get the reason.
1492     *
1493     * @throws IOException  If an I/O error occurs while either sending a
1494     *      command to the server or receiving a reply from the server.
1495     * @since 3.0
1496     */
1497    public String[] doCommandAsStrings(final String command, final String params) throws IOException
1498    {
1499        final boolean success = FTPReply.isPositiveCompletion(sendCommand(command, params));
1500        if (success){
1501            return getReplyStrings();
1502        }
1503        return null;
1504    }
1505
1506    /**
1507     * Set the current data connection mode to
1508     * <code>ACTIVE_LOCAL_DATA_CONNECTION_MODE</code>.  No communication
1509     * with the FTP server is conducted, but this causes all future data
1510     * transfers to require the FTP server to connect to the client's
1511     * data port.  Additionally, to accommodate differences between socket
1512     * implementations on different platforms, this method causes the
1513     * client to issue a PORT command before every data transfer.
1514     */
1515    public void enterLocalActiveMode()
1516    {
1517        dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE;
1518        passiveHost = null;
1519        passivePort = -1;
1520    }
1521
1522    /**
1523     * Set the current data connection mode to
1524     * <code> PASSIVE_LOCAL_DATA_CONNECTION_MODE </code>.  Use this
1525     * method only for data transfers between the client and server.
1526     * This method causes a PASV (or EPSV) command to be issued to the server
1527     * before the opening of every data connection, telling the server to
1528     * open a data port to which the client will connect to conduct
1529     * data transfers.  The FTPClient will stay in
1530     * <code> PASSIVE_LOCAL_DATA_CONNECTION_MODE </code> until the
1531     * mode is changed by calling some other method such as
1532     * {@link #enterLocalActiveMode  enterLocalActiveMode() }
1533     * <p>
1534     * <b>N.B.</b> currently calling any connect method will reset the mode to
1535     * ACTIVE_LOCAL_DATA_CONNECTION_MODE.
1536     */
1537    public void enterLocalPassiveMode()
1538    {
1539        dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE;
1540        // These will be set when just before a data connection is opened
1541        // in _openDataConnection_()
1542        passiveHost = null;
1543        passivePort = -1;
1544    }
1545
1546    /**
1547     * Set the current data connection mode to
1548     * <code> ACTIVE_REMOTE_DATA_CONNECTION </code>.  Use this method only
1549     * for server to server data transfers.  This method issues a PORT
1550     * command to the server, indicating the other server and port to which
1551     * it should connect for data transfers.  You must call this method
1552     * before EVERY server to server transfer attempt.  The FTPClient will
1553     * NOT automatically continue to issue PORT commands.  You also
1554     * must remember to call
1555     * {@link #enterLocalActiveMode  enterLocalActiveMode() } if you
1556     * wish to return to the normal data connection mode.
1557     *
1558     * @param host The passive mode server accepting connections for data
1559     *             transfers.
1560     * @param port The passive mode server's data port.
1561     * @return True if successfully completed, false if not.
1562     * @throws FTPConnectionClosedException
1563     *      If the FTP server prematurely closes the connection as a result
1564     *      of the client being idle or some other reason causing the server
1565     *      to send FTP reply code 421.  This exception may be caught either
1566     *      as an IOException or independently as itself.
1567     * @throws IOException  If an I/O error occurs while either sending a
1568     *      command to the server or receiving a reply from the server.
1569     */
1570    public boolean enterRemoteActiveMode(final InetAddress host, final int port)
1571    throws IOException
1572    {
1573        if (FTPReply.isPositiveCompletion(port(host, port)))
1574        {
1575            dataConnectionMode = ACTIVE_REMOTE_DATA_CONNECTION_MODE;
1576            passiveHost = null;
1577            passivePort = -1;
1578            return true;
1579        }
1580        return false;
1581    }
1582
1583    /**
1584     * Set the current data connection mode to
1585     * <code> PASSIVE_REMOTE_DATA_CONNECTION_MODE </code>.  Use this
1586     * method only for server to server data transfers.
1587     * This method issues a PASV command to the server, telling it to
1588     * open a data port to which the active server will connect to conduct
1589     * data transfers.  You must call this method
1590     * before EVERY server to server transfer attempt.  The FTPClient will
1591     * NOT automatically continue to issue PASV commands.  You also
1592     * must remember to call
1593     * {@link #enterLocalActiveMode  enterLocalActiveMode() } if you
1594     * wish to return to the normal data connection mode.
1595     *
1596     * @return True if successfully completed, false if not.
1597     * @throws FTPConnectionClosedException
1598     *      If the FTP server prematurely closes the connection as a result
1599     *      of the client being idle or some other reason causing the server
1600     *      to send FTP reply code 421.  This exception may be caught either
1601     *      as an IOException or independently as itself.
1602     * @throws IOException  If an I/O error occurs while either sending a
1603     *      command to the server or receiving a reply from the server.
1604     */
1605    public boolean enterRemotePassiveMode() throws IOException
1606    {
1607        if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) {
1608            return false;
1609        }
1610
1611        dataConnectionMode = PASSIVE_REMOTE_DATA_CONNECTION_MODE;
1612        _parsePassiveModeReply(_replyLines.get(0));
1613
1614        return true;
1615    }
1616
1617    /**
1618     * Queries the server for supported features. The server may reply with a list of server-supported extensions.
1619     * For example, a typical client-server interaction might be (from RFC 2389):
1620     * <pre>
1621        C&gt; feat
1622        S&gt; 211-Extensions supported:
1623        S&gt;  MLST size*;create;modify*;perm;media-type
1624        S&gt;  SIZE
1625        S&gt;  COMPRESSION
1626        S&gt;  MDTM
1627        S&gt; 211 END
1628     * </pre>
1629     * @see <a href="http://www.faqs.org/rfcs/rfc2389.html">http://www.faqs.org/rfcs/rfc2389.html</a>
1630     * @return True if successfully completed, false if not.
1631     * @throws IOException on error
1632     * @since 2.2
1633     */
1634    public boolean features() throws IOException {
1635        return FTPReply.isPositiveCompletion(feat());
1636    }
1637
1638    /**
1639     * Queries the server for a supported feature, and returns the its value (if any).
1640     * Caches the parsed response to avoid resending the command repeatedly.
1641     * @param feature the feature to check
1642     *
1643     * @return if the feature is present, returns the feature value or the empty string
1644     * if the feature exists but has no value.
1645     * Returns {@code null} if the feature is not found or the command failed.
1646     * Check {@link #getReplyCode()} or {@link #getReplyString()} if so.
1647     * @throws IOException on error
1648     * @since 3.0
1649     */
1650    public String featureValue(final String feature) throws IOException {
1651        final String [] values = featureValues(feature);
1652        if (values != null) {
1653            return values[0];
1654        }
1655        return null;
1656    }
1657
1658    /**
1659     * Queries the server for a supported feature, and returns its values (if any).
1660     * Caches the parsed response to avoid resending the command repeatedly.
1661     * @param feature the feature to check
1662     *
1663     * @return if the feature is present, returns the feature values (empty array if none)
1664     * Returns {@code null} if the feature is not found or the command failed.
1665     * Check {@link #getReplyCode()} or {@link #getReplyString()} if so.
1666     * @throws IOException on error
1667     * @since 3.0
1668     */
1669    public String[] featureValues(final String feature) throws IOException {
1670        if (!initFeatureMap()) {
1671            return null;
1672        }
1673        final Set<String> entries = featuresMap.get(feature.toUpperCase(Locale.ENGLISH));
1674        if (entries != null) {
1675            return entries.toArray(NetConstants.EMPTY_STRING_ARRAY);
1676        }
1677        return null;
1678    }
1679
1680    /**
1681     * Get the client port for active mode.
1682     *
1683     * @return The client port for active mode.
1684     */
1685    private int getActivePort()
1686    {
1687        if (activeMinPort > 0 && activeMaxPort >= activeMinPort)
1688        {
1689            if (activeMaxPort == activeMinPort) {
1690                return activeMaxPort;
1691            }
1692            // Get a random port between the min and max port range
1693            return random.nextInt(activeMaxPort - activeMinPort + 1) + activeMinPort;
1694        }
1695        // default port
1696        return 0;
1697    }
1698
1699    /**
1700     * Tells if automatic server encoding detection is enabled or disabled.
1701     * @return true, if automatic server encoding detection is enabled.
1702     */
1703    public boolean getAutodetectUTF8()
1704    {
1705        return autodetectEncoding;
1706    }
1707
1708    private InputStream getBufferedInputStream(final InputStream inputStream) {
1709        if (bufferSize > 0) {
1710            return new BufferedInputStream(inputStream, bufferSize);
1711        }
1712        return new BufferedInputStream(inputStream);
1713    }
1714
1715    private OutputStream getBufferedOutputStream(final OutputStream outputStream) {
1716        if (bufferSize > 0) {
1717            return new BufferedOutputStream(outputStream, bufferSize);
1718        }
1719        return new BufferedOutputStream(outputStream);
1720    }
1721
1722    /**
1723     * Retrieve the current internal buffer size for buffered data streams.
1724     * @return The current buffer size.
1725     */
1726    public int getBufferSize() {
1727        return bufferSize;
1728    }
1729
1730    /**
1731     * Gets how long to wait for control keep-alive message replies.
1732     * @return wait time in milliseconds.
1733     * @since 3.0
1734     */
1735    public int getControlKeepAliveReplyTimeout() {
1736        return controlKeepAliveReplyTimeoutMillis;
1737    }
1738
1739    /**
1740     * Gets the time to wait between sending control connection keepalive messages
1741     * when processing file upload or download.
1742     * <p>
1743     * See the class Javadoc section "Control channel keep-alive feature:"
1744     *
1745     * @return the number of seconds between keepalive messages.
1746     * @since 3.0
1747     */
1748    public long getControlKeepAliveTimeout() {
1749        return controlKeepAliveTimeoutMillis / 1000;
1750    }
1751
1752    /**
1753     * Obtain the currently active listener.
1754     *
1755     * @return the listener, may be {@code null}
1756     * @since 3.0
1757     */
1758    public CopyStreamListener getCopyStreamListener(){
1759        return copyStreamListener;
1760    }
1761
1762    /**
1763     * Get the CSL debug array.
1764     * <p>
1765     * <b>For debug use only</b>
1766     * <p>
1767     * Currently contains:
1768     * <ul>
1769     * <li>successfully acked NOOPs at end of transfer</li>
1770     * <li>unanswered NOOPs at end of transfer</li>
1771     * <li>unanswered NOOPs after fetching additional replies</li>
1772     * <li>Number of IOErrors ignored</li>
1773     * </ul>
1774     * @return the debug array
1775     * @deprecated 3.7 For testing only; may be dropped or changed at any time
1776     */
1777    @Deprecated // only for use in testing
1778    public int[] getCslDebug() {
1779        return cslDebug;
1780    }
1781
1782    /**
1783     * Returns the current data connection mode (one of the
1784     * <code> _DATA_CONNECTION_MODE </code> constants.
1785     *
1786     * @return The current data connection mode (one of the
1787     * <code> _DATA_CONNECTION_MODE </code> constants.
1788     */
1789    public int getDataConnectionMode()
1790    {
1791        return dataConnectionMode;
1792    }
1793
1794    // Method for use by unit test code only
1795    FTPFileEntryParser getEntryParser() {
1796        return entryParser;
1797    }
1798
1799    /**
1800     * Get the host address for active mode; allows the local address to be overridden.
1801     *
1802     * @return __activeExternalHost if non-null, else getLocalAddress()
1803     * @see #setActiveExternalIPAddress(String)
1804     */
1805    private InetAddress getHostAddress()
1806    {
1807        if (activeExternalHost != null)
1808        {
1809            return activeExternalHost;
1810        }
1811        // default local address
1812        return getLocalAddress();
1813    }
1814
1815    /**
1816     * @param pathname the initial pathname
1817     * @return the adjusted string with "-a" added if necessary
1818     * @since 2.0
1819     */
1820    protected String getListArguments(final String pathname) {
1821        if (getListHiddenFiles())
1822        {
1823            if (pathname != null)
1824            {
1825                final StringBuilder sb = new StringBuilder(pathname.length() + 3);
1826                sb.append("-a ");
1827                sb.append(pathname);
1828                return sb.toString();
1829            }
1830            return "-a";
1831        }
1832
1833        return pathname;
1834    }
1835
1836    /**
1837     * @see #setListHiddenFiles(boolean)
1838     * @return the current state
1839     * @since 2.0
1840     */
1841    public boolean getListHiddenFiles() {
1842        return this.listHiddenFiles;
1843    }
1844
1845    /**
1846     * Issue the FTP MDTM command (not supported by all servers) to retrieve the last
1847     * modification time of a file. The modification string should be in the
1848     * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in
1849     * GMT, but not all FTP servers honor this.
1850     *
1851     * @param pathname The file path to query.
1852     * @return A string representing the last file modification time in <code>YYYYMMDDhhmmss</code> format.
1853     * @throws IOException if an I/O error occurs.
1854     * @since 2.0
1855     */
1856    public String getModificationTime(final String pathname) throws IOException {
1857        if (FTPReply.isPositiveCompletion(mdtm(pathname))) {
1858            // skip the return code (e.g. 213) and the space
1859            return getReplyString(0).substring(4);
1860        }
1861        return null;
1862    }
1863
1864    /**
1865     * Returns the hostname or IP address (in the form of a string) returned
1866     * by the server when entering passive mode.  If not in passive mode,
1867     * returns null.  This method only returns a valid value AFTER a
1868     * data connection has been opened after a call to
1869     * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
1870     * This is because FTPClient sends a PASV command to the server only
1871     * just before opening a data connection, and not when you call
1872     * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
1873     *
1874     * @return The passive host name if in passive mode, otherwise null.
1875     */
1876    public String getPassiveHost()
1877    {
1878        return passiveHost;
1879    }
1880
1881    /**
1882     * Set the local IP address in passive mode.
1883     * Useful when there are multiple network cards.
1884     *
1885     * @return The local IP address in passive mode.
1886     */
1887    public InetAddress getPassiveLocalIPAddress()
1888    {
1889        return this.passiveLocalHost;
1890    }
1891
1892    /**
1893     * If in passive mode, returns the data port of the passive host.
1894     * This method only returns a valid value AFTER a
1895     * data connection has been opened after a call to
1896     * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
1897     * This is because FTPClient sends a PASV command to the server only
1898     * just before opening a data connection, and not when you call
1899     * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
1900     *
1901     * @return The data port of the passive server.  If not in passive
1902     *         mode, undefined.
1903     */
1904    public int getPassivePort()
1905    {
1906        return passivePort;
1907    }
1908
1909    /**
1910     * Retrieve the value to be used for the data socket SO_RCVBUF option.
1911     * @return The current buffer size.
1912     * @since 3.3
1913     */
1914    public int getReceiveDataSocketBufferSize() {
1915        return receiveDataSocketBufferSize;
1916    }
1917
1918    /**
1919     * Get the reported host address for active mode EPRT/PORT commands;
1920     * allows override of {@link #getHostAddress()}.
1921     *
1922     * Useful for FTP Client behind Firewall NAT.
1923     *
1924     * @return __reportActiveExternalHost if non-null, else getHostAddress();
1925     */
1926    private InetAddress getReportHostAddress() {
1927        if (reportActiveExternalHost != null) {
1928            return reportActiveExternalHost ;
1929        }
1930        return getHostAddress();
1931    }
1932
1933    /**
1934     * Fetches the restart offset.
1935     *
1936     * @return offset  The offset into the remote file at which to start the
1937     *           next file transfer.
1938     */
1939    public long getRestartOffset()
1940    {
1941        return restartOffset;
1942    }
1943
1944    /**
1945     * Retrieve the value to be used for the data socket SO_SNDBUF option.
1946     * @return The current buffer size.
1947     * @since 3.3
1948     */
1949    public int getSendDataSocketBufferSize() {
1950        return sendDataSocketBufferSize;
1951    }
1952
1953    /**
1954     * Issue the FTP SIZE command to the server for a given pathname.
1955     * This should produce the size of the file.
1956     *
1957     * @param pathname the file name
1958     *
1959     * @return The size information returned by the server; {@code null} if there was an error
1960     * @throws FTPConnectionClosedException
1961     *      If the FTP server prematurely closes the connection as a result
1962     *      of the client being idle or some other reason causing the server
1963     *      to send FTP reply code 421.  This exception may be caught either
1964     *      as an IOException or independently as itself.
1965     * @throws IOException  If an I/O error occurs while either sending a
1966     *      command to the server or receiving a reply from the server.
1967     * @since 3.7
1968     */
1969    public String getSize(final String pathname) throws IOException
1970    {
1971        if (FTPReply.isPositiveCompletion(size(pathname))) {
1972            return getReplyString(0).substring(4); // skip the return code (e.g. 213) and the space
1973        }
1974        return null;
1975    }
1976
1977    /**
1978     * Issue the FTP STAT command to the server.
1979     *
1980     * @return The status information returned by the server.
1981     * @throws FTPConnectionClosedException
1982     *      If the FTP server prematurely closes the connection as a result
1983     *      of the client being idle or some other reason causing the server
1984     *      to send FTP reply code 421.  This exception may be caught either
1985     *      as an IOException or independently as itself.
1986     * @throws IOException  If an I/O error occurs while either sending a
1987     *      command to the server or receiving a reply from the server.
1988     */
1989    public String getStatus() throws IOException
1990    {
1991        if (FTPReply.isPositiveCompletion(stat())) {
1992            return getReplyString();
1993        }
1994        return null;
1995    }
1996
1997    /**
1998     * Issue the FTP STAT command to the server for a given pathname.  This
1999     * should produce a listing of the file or directory.
2000     * @param pathname the file name
2001     *
2002     * @return The status information returned by the server.
2003     * @throws FTPConnectionClosedException
2004     *      If the FTP server prematurely closes the connection as a result
2005     *      of the client being idle or some other reason causing the server
2006     *      to send FTP reply code 421.  This exception may be caught either
2007     *      as an IOException or independently as itself.
2008     * @throws IOException  If an I/O error occurs while either sending a
2009     *      command to the server or receiving a reply from the server.
2010     */
2011    public String getStatus(final String pathname) throws IOException
2012    {
2013        if (FTPReply.isPositiveCompletion(stat(pathname))) {
2014            return getReplyString();
2015        }
2016        return null;
2017    }
2018
2019    /**
2020     * @return the name
2021     * @throws IOException on error
2022     * @deprecated use {@link #getSystemType()} instead
2023     */
2024    @Deprecated
2025    public String getSystemName() throws IOException
2026    {
2027        if (systemName == null && FTPReply.isPositiveCompletion(syst())) {
2028            systemName = _replyLines.get(_replyLines.size() - 1).substring(4);
2029        }
2030        return systemName;
2031    }
2032
2033    /**
2034     * Fetches the system type from the server and returns the string.
2035     * This value is cached for the duration of the connection after the
2036     * first call to this method.  In other words, only the first time
2037     * that you invoke this method will it issue a SYST command to the
2038     * FTP server.  FTPClient will remember the value and return the
2039     * cached value until a call to disconnect.
2040     * <p>
2041     * If the SYST command fails, and the system property
2042     * {@link #FTP_SYSTEM_TYPE_DEFAULT} is defined, then this is used instead.
2043     * @return The system type obtained from the server. Never null.
2044     * @throws FTPConnectionClosedException
2045     *      If the FTP server prematurely closes the connection as a result
2046     *      of the client being idle or some other reason causing the server
2047     *      to send FTP reply code 421.  This exception may be caught either
2048     *      as an IOException or independently as itself.
2049     * @throws IOException  If an I/O error occurs while either sending a
2050     *  command to the server or receiving a reply from the server (and the default
2051     *  system type property is not defined)
2052     *  @since 2.2
2053     */
2054    public String getSystemType() throws IOException
2055    {
2056        //if (syst() == FTPReply.NAME_SYSTEM_TYPE)
2057        // Technically, we should expect a NAME_SYSTEM_TYPE response, but
2058        // in practice FTP servers deviate, so we soften the condition to
2059        // a positive completion.
2060        if (systemName == null){
2061            if (FTPReply.isPositiveCompletion(syst())) {
2062                // Assume that response is not empty here (cannot be null)
2063                systemName = _replyLines.get(_replyLines.size() - 1).substring(4);
2064            } else {
2065                // Check if the user has provided a default for when the SYST command fails
2066                final String systDefault = System.getProperty(FTP_SYSTEM_TYPE_DEFAULT);
2067                if (systDefault != null) {
2068                    systemName = systDefault;
2069                } else {
2070                    throw new IOException("Unable to determine system type - response: " + getReplyString());
2071                }
2072            }
2073        }
2074        return systemName;
2075    }
2076
2077    /**
2078     * Queries the server for a supported feature.
2079     * Caches the parsed response to avoid resending the command repeatedly.
2080     *
2081     * @param feature the name of the feature; it is converted to upper case.
2082     * @return {@code true} if the feature is present, {@code false} if the feature is not present
2083     * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()}
2084     * if it is necessary to distinguish these cases.
2085     *
2086     * @throws IOException on error
2087     * @since 3.8.0
2088     */
2089    public boolean hasFeature(final FTPCmd feature) throws IOException {
2090        return hasFeature(feature.name());
2091    }
2092
2093    /**
2094     * Queries the server for a supported feature.
2095     * Caches the parsed response to avoid resending the command repeatedly.
2096     *
2097     * @param feature the name of the feature; it is converted to upper case.
2098     * @return {@code true} if the feature is present, {@code false} if the feature is not present
2099     * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()}
2100     * if it is necessary to distinguish these cases.
2101     *
2102     * @throws IOException on error
2103     * @since 3.0
2104     */
2105    public boolean hasFeature(final String feature) throws IOException {
2106        if (!initFeatureMap()) {
2107            return false;
2108        }
2109        return featuresMap.containsKey(feature.toUpperCase(Locale.ENGLISH));
2110    }
2111
2112    /**
2113     * Queries the server for a supported feature with particular value,
2114     * for example "AUTH SSL" or "AUTH TLS".
2115     * Caches the parsed response to avoid resending the command repeatedly.
2116     *
2117     * @param feature the name of the feature; it is converted to upper case.
2118     * @param value the value to find.
2119     *
2120     * @return {@code true} if the feature is present, {@code false} if the feature is not present
2121     * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()}
2122     * if it is necessary to distinguish these cases.
2123     *
2124     * @throws IOException on error
2125     * @since 3.0
2126     */
2127    public boolean hasFeature(final String feature, final String value) throws IOException {
2128        if (!initFeatureMap()) {
2129            return false;
2130        }
2131        final Set<String> entries = featuresMap.get(feature.toUpperCase(Locale.ENGLISH));
2132        if (entries != null) {
2133            return entries.contains(value);
2134        }
2135        return false;
2136    }
2137
2138    private void initDefaults()
2139    {
2140        dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE;
2141        passiveHost        = null;
2142        passivePort        = -1;
2143        activeExternalHost = null;
2144        reportActiveExternalHost = null;
2145        activeMinPort = 0;
2146        activeMaxPort = 0;
2147        fileType           = FTP.ASCII_FILE_TYPE;
2148        fileStructure      = FTP.FILE_STRUCTURE;
2149        fileFormat         = FTP.NON_PRINT_TEXT_FORMAT;
2150        fileTransferMode   = FTP.STREAM_TRANSFER_MODE;
2151        restartOffset      = 0;
2152        systemName         = null;
2153        entryParser        = null;
2154        entryParserKey    = "";
2155        featuresMap = null;
2156    }
2157
2158    /*
2159     * Create the feature map if not already created.
2160     */
2161    private boolean initFeatureMap() throws IOException {
2162        if (featuresMap == null) {
2163            // Don't create map here, because next line may throw exception
2164            final int replyCode = feat();
2165            if (replyCode == FTPReply.NOT_LOGGED_IN) { // 503
2166                return false; // NET-518; don't create empy map
2167            }
2168            final boolean success = FTPReply.isPositiveCompletion(replyCode);
2169            // we init the map here, so we don't keep trying if we know the command will fail
2170            featuresMap = new HashMap<>();
2171            if (!success) {
2172                return false;
2173            }
2174            for (final String line : _replyLines) {
2175                if (line.startsWith(" ")) { // it's a FEAT entry
2176                    String key;
2177                    String value = "";
2178                    final int varsep = line.indexOf(' ', 1);
2179                    if (varsep > 0) {
2180                        key = line.substring(1, varsep);
2181                        value = line.substring(varsep + 1);
2182                    } else {
2183                        key = line.substring(1);
2184                    }
2185                    key = key.toUpperCase(Locale.ENGLISH);
2186                    Set<String> entries = featuresMap.get(key);
2187                    if (entries == null) {
2188                        entries = new HashSet<>();
2189                        featuresMap.put(key, entries);
2190                    }
2191                    entries.add(value);
2192                }
2193            }
2194        }
2195        return true;
2196    }
2197
2198    /**
2199     * Using the default autodetect mechanism, initialize an FTPListParseEngine
2200     * object containing a raw file information for the current working
2201     * directory on the server
2202     * This information is obtained through the LIST command.  This object
2203     * is then capable of being iterated to return a sequence of FTPFile
2204     * objects with information filled in by the
2205     * <code> FTPFileEntryParser </code> used.
2206     * <p>
2207     * This method differs from using the listFiles() methods in that
2208     * expensive FTPFile objects are not created until needed which may be
2209     * an advantage on large lists.
2210     *
2211     * @return A FTPListParseEngine object that holds the raw information and
2212     * is capable of providing parsed FTPFile objects, one for each file
2213     * containing information contained in the given path in the format
2214     * determined by the <code> parser </code> parameter.   Null will be
2215     * returned if a data connection cannot be opened.  If the current working
2216     * directory contains no files, an empty array will be the return.
2217     *
2218     * @throws FTPConnectionClosedException
2219     *                   If the FTP server prematurely closes the connection as a result
2220     *                   of the client being idle or some other reason causing the server
2221     *                   to send FTP reply code 421.  This exception may be caught either
2222     *                   as an IOException or independently as itself.
2223     * @throws IOException
2224     *                   If an I/O error occurs while either sending a
2225     *                   command to the server or receiving a reply from the server.
2226     * @throws org.apache.commons.net.ftp.parser.ParserInitializationException
2227     *                   Thrown if the autodetect mechanism cannot
2228     *                   resolve the type of system we are connected with.
2229     * @see FTPListParseEngine
2230     */
2231    public FTPListParseEngine initiateListParsing()
2232    throws IOException
2233    {
2234        return initiateListParsing((String) null);
2235    }
2236
2237    /**
2238     * private method through which all listFiles() and
2239     * initiateListParsing methods pass once a parser is determined.
2240     *
2241     * @throws FTPConnectionClosedException
2242     *                   If the FTP server prematurely closes the connection as a result
2243     *                   of the client being idle or some other reason causing the server
2244     *                   to send FTP reply code 421.  This exception may be caught either
2245     *                   as an IOException or independently as itself.
2246     * @throws IOException
2247     *                   If an I/O error occurs while either sending a
2248     *                   command to the server or receiving a reply from the server.
2249     * @see FTPListParseEngine
2250     */
2251    private FTPListParseEngine initiateListParsing(
2252            final FTPFileEntryParser parser, final String pathname)
2253    throws IOException
2254    {
2255        final Socket socket = _openDataConnection_(FTPCmd.LIST, getListArguments(pathname));
2256
2257        final FTPListParseEngine engine = new FTPListParseEngine(parser, configuration);
2258        if (socket == null)
2259        {
2260            return engine;
2261        }
2262
2263        try {
2264            engine.readServerList(socket.getInputStream(), getControlEncoding());
2265        }
2266        finally {
2267            Util.closeQuietly(socket);
2268        }
2269
2270        completePendingCommand();
2271        return engine;
2272    }
2273
2274    /**
2275     * Using the default autodetect mechanism, initialize an FTPListParseEngine
2276     * object containing a raw file information for the supplied directory.
2277     * This information is obtained through the LIST command.  This object
2278     * is then capable of being iterated to return a sequence of FTPFile
2279     * objects with information filled in by the
2280     * <code> FTPFileEntryParser </code> used.
2281     * <p>
2282     * The server may or may not expand glob expressions.  You should avoid
2283     * using glob expressions because the return format for glob listings
2284     * differs from server to server and will likely cause this method to fail.
2285     * <p>
2286     * This method differs from using the listFiles() methods in that
2287     * expensive FTPFile objects are not created until needed which may be
2288     * an advantage on large lists.
2289     *
2290     * <pre>
2291     *    FTPClient f=FTPClient();
2292     *    f.connect(server);
2293     *    f.login(username, password);
2294     *    FTPListParseEngine engine = f.initiateListParsing(directory);
2295     *
2296     *    while (engine.hasNext()) {
2297     *       FTPFile[] files = engine.getNext(25);  // "page size" you want
2298     *       //do whatever you want with these files, display them, etc.
2299     *       //expensive FTPFile objects not created until needed.
2300     *    }
2301     * </pre>
2302     * @param pathname the starting directory
2303     *
2304     * @return A FTPListParseEngine object that holds the raw information and
2305     * is capable of providing parsed FTPFile objects, one for each file
2306     * containing information contained in the given path in the format
2307     * determined by the <code> parser </code> parameter.   Null will be
2308     * returned if a data connection cannot be opened.  If the current working
2309     * directory contains no files, an empty array will be the return.
2310     *
2311     * @throws FTPConnectionClosedException
2312     *                   If the FTP server prematurely closes the connection as a result
2313     *                   of the client being idle or some other reason causing the server
2314     *                   to send FTP reply code 421.  This exception may be caught either
2315     *                   as an IOException or independently as itself.
2316     * @throws IOException
2317     *                   If an I/O error occurs while either sending a
2318     *                   command to the server or receiving a reply from the server.
2319     * @throws org.apache.commons.net.ftp.parser.ParserInitializationException
2320     *                   Thrown if the autodetect mechanism cannot
2321     *                   resolve the type of system we are connected with.
2322     * @see FTPListParseEngine
2323     */
2324    public FTPListParseEngine initiateListParsing(final String pathname)
2325    throws IOException
2326    {
2327        return initiateListParsing((String) null, pathname);
2328    }
2329
2330    /**
2331     * Using the supplied parser key, initialize an FTPListParseEngine
2332     * object containing a raw file information for the supplied directory.
2333     * This information is obtained through the LIST command.  This object
2334     * is then capable of being iterated to return a sequence of FTPFile
2335     * objects with information filled in by the
2336     * <code> FTPFileEntryParser </code> used.
2337     * <p>
2338     * The server may or may not expand glob expressions.  You should avoid
2339     * using glob expressions because the return format for glob listings
2340     * differs from server to server and will likely cause this method to fail.
2341     * <p>
2342     * This method differs from using the listFiles() methods in that
2343     * expensive FTPFile objects are not created until needed which may be
2344     * an advantage on large lists.
2345     *
2346     * @param parserKey A string representing a designated code or fully-qualified
2347     * class name of an  <code> FTPFileEntryParser </code> that should be
2348     *               used to parse each server file listing.
2349     *               May be {@code null}, in which case the code checks first
2350     *               the system property {@link #FTP_SYSTEM_TYPE}, and if that is
2351     *               not defined the SYST command is used to provide the value.
2352     *               To allow for arbitrary system types, the return from the
2353     *               SYST command is used to look up an alias for the type in the
2354     *               {@link #SYSTEM_TYPE_PROPERTIES} properties file if it is available.
2355     * @param pathname the starting directory
2356     *
2357     * @return A FTPListParseEngine object that holds the raw information and
2358     * is capable of providing parsed FTPFile objects, one for each file
2359     * containing information contained in the given path in the format
2360     * determined by the <code> parser </code> parameter.   Null will be
2361     * returned if a data connection cannot be opened.  If the current working
2362     * directory contains no files, an empty array will be the return.
2363     *
2364     * @throws FTPConnectionClosedException
2365     *                   If the FTP server prematurely closes the connection as a result
2366     *                   of the client being idle or some other reason causing the server
2367     *                   to send FTP reply code 421.  This exception may be caught either
2368     *                   as an IOException or independently as itself.
2369     * @throws IOException
2370     *                   If an I/O error occurs while either sending a
2371     *                   command to the server or receiving a reply from the server.
2372     * @throws org.apache.commons.net.ftp.parser.ParserInitializationException
2373     *                   Thrown if the parserKey parameter cannot be
2374     *                   resolved by the selected parser factory.
2375     *                   In the DefaultFTPEntryParserFactory, this will
2376     *                   happen when parserKey is neither
2377     *                   the fully qualified class name of a class
2378     *                   implementing the interface
2379     *                   org.apache.commons.net.ftp.FTPFileEntryParser
2380     *                   nor a string containing one of the recognized keys
2381     *                   mapping to such a parser or if class loader
2382     *                   security issues prevent its being loaded.
2383     * @see FTPListParseEngine
2384     */
2385    public FTPListParseEngine initiateListParsing(
2386            final String parserKey, final String pathname)
2387    throws IOException
2388    {
2389        createParser(parserKey); // create and cache parser
2390        return initiateListParsing(entryParser, pathname);
2391    }
2392
2393    /**
2394     * Initiate list parsing for MLSD listings in the current working directory.
2395     *
2396     * @return the engine
2397     * @throws IOException on error
2398     */
2399    public FTPListParseEngine initiateMListParsing() throws IOException
2400    {
2401        return initiateMListParsing(null);
2402    }
2403
2404    /**
2405     * Initiate list parsing for MLSD listings.
2406     *
2407     * @param pathname the path from where to MLSD.
2408     * @return the engine.
2409     * @throws IOException on error
2410     */
2411    public FTPListParseEngine initiateMListParsing(final String pathname) throws IOException
2412    {
2413        final Socket socket = _openDataConnection_(FTPCmd.MLSD, pathname);
2414        final FTPListParseEngine engine = new FTPListParseEngine(MLSxEntryParser.getInstance(), configuration);
2415        if (socket == null)
2416        {
2417            return engine;
2418        }
2419
2420        try {
2421            engine.readServerList(socket.getInputStream(), getControlEncoding());
2422        }
2423        finally {
2424            Util.closeQuietly(socket);
2425            completePendingCommand();
2426        }
2427        return engine;
2428    }
2429
2430    /**
2431     * Return whether or not verification of the remote host participating
2432     * in data connections is enabled.  The default behavior is for
2433     * verification to be enabled.
2434     *
2435     * @return True if verification is enabled, false if not.
2436     */
2437    public boolean isRemoteVerificationEnabled()
2438    {
2439        return remoteVerificationEnabled;
2440    }
2441
2442    /**
2443     * Whether should attempt to use EPSV with IPv4.
2444     * Default (if not set) is <code>false</code>
2445     * @return true if should attempt EPSV
2446     * @since 2.2
2447     */
2448    public boolean isUseEPSVwithIPv4() {
2449        return useEPSVwithIPv4;
2450    }
2451
2452    /**
2453     * Using the default system autodetect mechanism, obtain a
2454     * list of directories contained in the current working directory.
2455     * <p>
2456     * This information is obtained through the LIST command.  The contents of
2457     * the returned array is determined by the<code> FTPFileEntryParser </code>
2458     * used.
2459     * <p>
2460     * N.B. the LIST command does not generally return very precise timestamps.
2461     * For recent files, the response usually contains hours and minutes (not seconds).
2462     * For older files, the output may only contain a date.
2463     * If the server supports it, the MLSD command returns timestamps with a precision
2464     * of seconds, and may include milliseconds. See {@link #mlistDir()}
2465     *
2466     * @return The list of directories contained in the current directory
2467     *         in the format determined by the autodetection mechanism.
2468     *
2469     * @throws FTPConnectionClosedException
2470     *                   If the FTP server prematurely closes the connection
2471     *                   as a result of the client being idle or some other
2472     *                   reason causing the server to send FTP reply code 421.
2473     *                   This exception may be caught either as an IOException
2474     *                   or independently as itself.
2475     * @throws IOException
2476     *                   If an I/O error occurs while either sending a
2477     *                   command to the server or receiving a reply
2478     *                   from the server.
2479     * @throws org.apache.commons.net.ftp.parser.ParserInitializationException
2480     *                   Thrown if the parserKey parameter cannot be
2481     *                   resolved by the selected parser factory.
2482     *                   In the DefaultFTPEntryParserFactory, this will
2483     *                   happen when parserKey is neither
2484     *                   the fully qualified class name of a class
2485     *                   implementing the interface
2486     *                   org.apache.commons.net.ftp.FTPFileEntryParser
2487     *                   nor a string containing one of the recognized keys
2488     *                   mapping to such a parser or if class loader
2489     *                   security issues prevent its being loaded.
2490     * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
2491     * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
2492     * @see org.apache.commons.net.ftp.FTPFileEntryParser
2493     * @since 3.0
2494     */
2495    public FTPFile[] listDirectories() throws IOException {
2496        return listDirectories((String) null);
2497    }
2498
2499    /**
2500     * Using the default system autodetect mechanism, obtain a
2501     * list of directories contained in the specified directory.
2502     * <p>
2503     * This information is obtained through the LIST command.  The contents of
2504     * the returned array is determined by the<code> FTPFileEntryParser </code>
2505     * used.
2506     * <p>
2507     * N.B. the LIST command does not generally return very precise timestamps.
2508     * For recent files, the response usually contains hours and minutes (not seconds).
2509     * For older files, the output may only contain a date.
2510     * If the server supports it, the MLSD command returns timestamps with a precision
2511     * of seconds, and may include milliseconds. See {@link #mlistDir()}
2512     * @param parent the starting directory
2513     *
2514     * @return The list of directories contained in the specified directory
2515     *         in the format determined by the autodetection mechanism.
2516     *
2517     * @throws FTPConnectionClosedException
2518     *                   If the FTP server prematurely closes the connection
2519     *                   as a result of the client being idle or some other
2520     *                   reason causing the server to send FTP reply code 421.
2521     *                   This exception may be caught either as an IOException
2522     *                   or independently as itself.
2523     * @throws IOException
2524     *                   If an I/O error occurs while either sending a
2525     *                   command to the server or receiving a reply
2526     *                   from the server.
2527     * @throws org.apache.commons.net.ftp.parser.ParserInitializationException
2528     *                   Thrown if the parserKey parameter cannot be
2529     *                   resolved by the selected parser factory.
2530     *                   In the DefaultFTPEntryParserFactory, this will
2531     *                   happen when parserKey is neither
2532     *                   the fully qualified class name of a class
2533     *                   implementing the interface
2534     *                   org.apache.commons.net.ftp.FTPFileEntryParser
2535     *                   nor a string containing one of the recognized keys
2536     *                   mapping to such a parser or if class loader
2537     *                   security issues prevent its being loaded.
2538     * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
2539     * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
2540     * @see org.apache.commons.net.ftp.FTPFileEntryParser
2541     * @since 3.0
2542     */
2543    public FTPFile[] listDirectories(final String parent) throws IOException {
2544        return listFiles(parent, FTPFileFilters.DIRECTORIES);
2545    }
2546
2547    /**
2548     * Using the default system autodetect mechanism, obtain a
2549     * list of file information for the current working directory.
2550     * <p>
2551     * This information is obtained through the LIST command.  The contents of
2552     * the returned array is determined by the<code> FTPFileEntryParser </code>
2553     * used.
2554     * <p>
2555     * N.B. the LIST command does not generally return very precise timestamps.
2556     * For recent files, the response usually contains hours and minutes (not seconds).
2557     * For older files, the output may only contain a date.
2558     * If the server supports it, the MLSD command returns timestamps with a precision
2559     * of seconds, and may include milliseconds. See {@link #mlistDir()}
2560     *
2561     * @return The list of file information contained in the current directory
2562     *         in the format determined by the autodetection mechanism.
2563     *         <p><b>
2564     *         NOTE:</b> This array may contain null members if any of the
2565     *         individual file listings failed to parse.  The caller should
2566     *         check each entry for null before referencing it.
2567     * @throws FTPConnectionClosedException
2568     *                   If the FTP server prematurely closes the connection
2569     *                   as a result of the client being idle or some other
2570     *                   reason causing the server to send FTP reply code 421.
2571     *                   This exception may be caught either as an IOException
2572     *                   or independently as itself.
2573     * @throws IOException
2574     *                   If an I/O error occurs while either sending a
2575     *                   command to the server or receiving a reply
2576     *                   from the server.
2577     * @throws org.apache.commons.net.ftp.parser.ParserInitializationException
2578     *                   Thrown if the parserKey parameter cannot be
2579     *                   resolved by the selected parser factory.
2580     *                   In the DefaultFTPEntryParserFactory, this will
2581     *                   happen when parserKey is neither
2582     *                   the fully qualified class name of a class
2583     *                   implementing the interface
2584     *                   org.apache.commons.net.ftp.FTPFileEntryParser
2585     *                   nor a string containing one of the recognized keys
2586     *                   mapping to such a parser or if class loader
2587     *                   security issues prevent its being loaded.
2588     * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
2589     * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
2590     * @see org.apache.commons.net.ftp.FTPFileEntryParser
2591     */
2592    public FTPFile[] listFiles()
2593    throws IOException
2594    {
2595        return listFiles((String) null);
2596    }
2597
2598    /**
2599     * Using the default system autodetect mechanism, obtain a
2600     * list of file information for the current working directory
2601     * or for just a single file.
2602     * <p>
2603     * This information is obtained through the LIST command.  The contents of
2604     * the returned array is determined by the<code> FTPFileEntryParser </code>
2605     * used.
2606     * <p>
2607     * N.B. the LIST command does not generally return very precise timestamps.
2608     * For recent files, the response usually contains hours and minutes (not seconds).
2609     * For older files, the output may only contain a date.
2610     * If the server supports it, the MLSD command returns timestamps with a precision
2611     * of seconds, and may include milliseconds. See {@link #mlistDir()}
2612     *
2613     * @param pathname  The file or directory to list.  Since the server may
2614     *                  or may not expand glob expressions, using them here
2615     *                  is not recommended and may well cause this method to
2616     *                  fail.
2617     *                  Also, some servers treat a leading '-' as being an option.
2618     *                  To avoid this interpretation, use an absolute pathname
2619     *                  or prefix the pathname with ./ (unix style servers).
2620     *                  Some servers may support "--" as meaning end of options,
2621     *                  in which case "-- -xyz" should work.
2622     *
2623     * @return The list of file information contained in the given path in
2624     *         the format determined by the autodetection mechanism
2625     * @throws FTPConnectionClosedException
2626     *                   If the FTP server prematurely closes the connection
2627     *                   as a result of the client being idle or some other
2628     *                   reason causing the server to send FTP reply code 421.
2629     *                   This exception may be caught either as an IOException
2630     *                   or independently as itself.
2631     * @throws IOException
2632     *                   If an I/O error occurs while either sending a
2633     *                   command to the server or receiving a reply
2634     *                   from the server.
2635     * @throws org.apache.commons.net.ftp.parser.ParserInitializationException
2636     *                   Thrown if the parserKey parameter cannot be
2637     *                   resolved by the selected parser factory.
2638     *                   In the DefaultFTPEntryParserFactory, this will
2639     *                   happen when parserKey is neither
2640     *                   the fully qualified class name of a class
2641     *                   implementing the interface
2642     *                   org.apache.commons.net.ftp.FTPFileEntryParser
2643     *                   nor a string containing one of the recognized keys
2644     *                   mapping to such a parser or if class loader
2645     *                   security issues prevent its being loaded.
2646     * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
2647     * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
2648     * @see org.apache.commons.net.ftp.FTPFileEntryParser
2649     */
2650    public FTPFile[] listFiles(final String pathname) throws IOException {
2651        return initiateListParsing((String) null, pathname).getFiles();
2652    }
2653
2654    /**
2655     * Version of {@link #listFiles(String)} which allows a filter to be provided.
2656     * For example: <code>listFiles("site", FTPFileFilters.DIRECTORY);</code>
2657     * @param pathname the initial path, may be null
2658     * @param filter the filter, non-null
2659     * @return the list of FTPFile entries.
2660     * @throws IOException on error
2661     * @since 2.2
2662     */
2663    public FTPFile[] listFiles(final String pathname, final FTPFileFilter filter) throws IOException {
2664        return initiateListParsing((String) null, pathname).getFiles(filter);
2665    }
2666
2667    /**
2668     * Fetches the system help information from the server and returns the
2669     * full string.
2670     *
2671     * @return The system help string obtained from the server.  null if the
2672     *       information could not be obtained.
2673     * @throws FTPConnectionClosedException
2674     *      If the FTP server prematurely closes the connection as a result
2675     *      of the client being idle or some other reason causing the server
2676     *      to send FTP reply code 421.  This exception may be caught either
2677     *      as an IOException or independently as itself.
2678     * @throws IOException  If an I/O error occurs while either sending a
2679     *  command to the server or receiving a reply from the server.
2680     */
2681    public String listHelp() throws IOException {
2682        return FTPReply.isPositiveCompletion(help()) ? getReplyString() : null;
2683    }
2684
2685    /**
2686     * Fetches the help information for a given command from the server and
2687     * returns the full string.
2688     * @param command The command on which to ask for help.
2689     * @return The command help string obtained from the server.  null if the
2690     *       information could not be obtained.
2691     * @throws FTPConnectionClosedException
2692     *      If the FTP server prematurely closes the connection as a result
2693     *      of the client being idle or some other reason causing the server
2694     *      to send FTP reply code 421.  This exception may be caught either
2695     *      as an IOException or independently as itself.
2696     * @throws IOException  If an I/O error occurs while either sending a
2697     *  command to the server or receiving a reply from the server.
2698     */
2699    public String listHelp(final String command) throws IOException {
2700        return FTPReply.isPositiveCompletion(help(command)) ? getReplyString() : null;
2701    }
2702
2703    /**
2704     * Obtain a list of file names in the current working directory
2705     * This information is obtained through the NLST command.  If the current
2706     * directory contains no files, a zero length array is returned only
2707     * if the FTP server returned a positive completion code, otherwise,
2708     * null is returned (the FTP server returned a 550 error No files found.).
2709     * If the directory is not empty, an array of file names in the directory is
2710     * returned.
2711     *
2712     * @return The list of file names contained in the current working
2713     *     directory.  null if the list could not be obtained.
2714     *     If there are no file names in the directory, a zero-length array
2715     *     is returned.
2716     * @throws FTPConnectionClosedException
2717     *      If the FTP server prematurely closes the connection as a result
2718     *      of the client being idle or some other reason causing the server
2719     *      to send FTP reply code 421.  This exception may be caught either
2720     *      as an IOException or independently as itself.
2721     * @throws IOException  If an I/O error occurs while either sending a
2722     *      command to the server or receiving a reply from the server.
2723     */
2724    public String[] listNames() throws IOException
2725    {
2726        return listNames(null);
2727    }
2728
2729    /**
2730     * Obtain a list of file names in a directory (or just the name of a given
2731     * file, which is not particularly useful).  This information is obtained
2732     * through the NLST command.  If the given pathname is a directory and
2733     * contains no files,  a zero length array is returned only
2734     * if the FTP server returned a positive completion code, otherwise
2735     * null is returned (the FTP server returned a 550 error No files found.).
2736     * If the directory is not empty, an array of file names in the directory is
2737     * returned. If the pathname corresponds
2738     * to a file, only that file will be listed.  The server may or may not
2739     * expand glob expressions.
2740     *
2741     * @param pathname  The file or directory to list.
2742     *                  Warning: the server may treat a leading '-' as an
2743     *                  option introducer. If so, try using an absolute path,
2744     *                  or prefix the path with ./ (unix style servers).
2745     *                  Some servers may support "--" as meaning end of options,
2746     *                  in which case "-- -xyz" should work.
2747     * @return The list of file names contained in the given path.  null if
2748     *     the list could not be obtained.  If there are no file names in
2749     *     the directory, a zero-length array is returned.
2750     * @throws FTPConnectionClosedException
2751     *      If the FTP server prematurely closes the connection as a result
2752     *      of the client being idle or some other reason causing the server
2753     *      to send FTP reply code 421.  This exception may be caught either
2754     *      as an IOException or independently as itself.
2755     * @throws IOException  If an I/O error occurs while either sending a
2756     *      command to the server or receiving a reply from the server.
2757     */
2758    public String[] listNames(final String pathname) throws IOException
2759    {
2760        final ArrayList<String> results = new ArrayList<>();
2761        try (final Socket socket = _openDataConnection_(FTPCmd.NLST, getListArguments(pathname))) {
2762
2763            if (socket == null) {
2764                return null;
2765            }
2766
2767            try (final BufferedReader reader = new BufferedReader(
2768                    new InputStreamReader(socket.getInputStream(), getControlEncoding()))) {
2769
2770                String line;
2771                while ((line = reader.readLine()) != null) {
2772                    results.add(line);
2773                }
2774            }
2775        }
2776
2777        if (completePendingCommand()) {
2778            return results.toArray(NetConstants.EMPTY_STRING_ARRAY);
2779        }
2780
2781        return null;
2782    }
2783
2784    /**
2785     * Login to the FTP server using the provided username and password.
2786     *
2787     * @param username The username to login under.
2788     * @param password The password to use.
2789     * @return True if successfully completed, false if not.
2790     * @throws FTPConnectionClosedException
2791     *      If the FTP server prematurely closes the connection as a result
2792     *      of the client being idle or some other reason causing the server
2793     *      to send FTP reply code 421.  This exception may be caught either
2794     *      as an IOException or independently as itself.
2795     * @throws IOException  If an I/O error occurs while either sending a
2796     *      command to the server or receiving a reply from the server.
2797     */
2798    public boolean login(final String username, final String password) throws IOException
2799    {
2800
2801        user(username);
2802
2803        if (FTPReply.isPositiveCompletion(_replyCode)) {
2804            return true;
2805        }
2806
2807        // If we get here, we either have an error code, or an intermmediate
2808        // reply requesting password.
2809        if (!FTPReply.isPositiveIntermediate(_replyCode)) {
2810            return false;
2811        }
2812
2813        return FTPReply.isPositiveCompletion(pass(password));
2814    }
2815
2816    /**
2817     * Login to the FTP server using the provided username, password,
2818     * and account.  If no account is required by the server, only
2819     * the username and password, the account information is not used.
2820     *
2821     * @param username The username to login under.
2822     * @param password The password to use.
2823     * @param account  The account to use.
2824     * @return True if successfully completed, false if not.
2825     * @throws FTPConnectionClosedException
2826     *      If the FTP server prematurely closes the connection as a result
2827     *      of the client being idle or some other reason causing the server
2828     *      to send FTP reply code 421.  This exception may be caught either
2829     *      as an IOException or independently as itself.
2830     * @throws IOException  If an I/O error occurs while either sending a
2831     *      command to the server or receiving a reply from the server.
2832     */
2833    public boolean login(final String username, final String password, final String account)
2834    throws IOException
2835    {
2836        user(username);
2837
2838        if (FTPReply.isPositiveCompletion(_replyCode)) {
2839            return true;
2840        }
2841
2842        // If we get here, we either have an error code, or an intermmediate
2843        // reply requesting password.
2844        if (!FTPReply.isPositiveIntermediate(_replyCode)) {
2845            return false;
2846        }
2847
2848        pass(password);
2849
2850        if (FTPReply.isPositiveCompletion(_replyCode)) {
2851            return true;
2852        }
2853
2854        if (!FTPReply.isPositiveIntermediate(_replyCode)) {
2855            return false;
2856        }
2857
2858        return FTPReply.isPositiveCompletion(acct(account));
2859    }
2860
2861    /**
2862     * Logout of the FTP server by sending the QUIT command.
2863     *
2864     * @return True if successfully completed, false if not.
2865     * @throws FTPConnectionClosedException
2866     *      If the FTP server prematurely closes the connection as a result
2867     *      of the client being idle or some other reason causing the server
2868     *      to send FTP reply code 421.  This exception may be caught either
2869     *      as an IOException or independently as itself.
2870     * @throws IOException  If an I/O error occurs while either sending a
2871     *      command to the server or receiving a reply from the server.
2872     */
2873    public boolean logout() throws IOException
2874    {
2875        return FTPReply.isPositiveCompletion(quit());
2876    }
2877
2878    /**
2879     * Creates a new subdirectory on the FTP server in the current directory
2880     * (if a relative pathname is given) or where specified (if an absolute
2881     * pathname is given).
2882     *
2883     * @param pathname The pathname of the directory to create.
2884     * @return True if successfully completed, false if not.
2885     * @throws FTPConnectionClosedException
2886     *      If the FTP server prematurely closes the connection as a result
2887     *      of the client being idle or some other reason causing the server
2888     *      to send FTP reply code 421.  This exception may be caught either
2889     *      as an IOException or independently as itself.
2890     * @throws IOException  If an I/O error occurs while either sending a
2891     *      command to the server or receiving a reply from the server.
2892     */
2893    public boolean makeDirectory(final String pathname) throws IOException
2894    {
2895        return FTPReply.isPositiveCompletion(mkd(pathname));
2896    }
2897
2898    /**
2899     * Issue the FTP MDTM command (not supported by all servers) to retrieve the last
2900     * modification time of a file. The modification string should be in the
2901     * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in
2902     * GMT, but not all FTP servers honor this.
2903     *
2904     * @param pathname The file path to query.
2905     * @return A Calendar representing the last file modification time, may be {@code null}.
2906     * The Calendar timestamp will be null if a parse error occurs.
2907     * @throws IOException if an I/O error occurs.
2908     * @since 3.8.0
2909     */
2910    public Calendar mdtmCalendar(final String pathname) throws IOException {
2911        final String modificationTime = getModificationTime(pathname);
2912        if (modificationTime != null) {
2913            return MLSxEntryParser.parseGMTdateTime(modificationTime);
2914        }
2915        return null;
2916    }
2917
2918    /**
2919     * Issue the FTP MDTM command (not supported by all servers) to retrieve the last
2920     * modification time of a file. The modification string should be in the
2921     * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in
2922     * GMT, but not all FTP servers honor this.
2923     *
2924     * @param pathname The file path to query.
2925     * @return A FTPFile representing the last file modification time, may be {@code null}.
2926     * The FTPFile timestamp will be null if a parse error occurs.
2927     * @throws IOException if an I/O error occurs.
2928     * @since 3.4
2929     */
2930    public FTPFile mdtmFile(final String pathname) throws IOException {
2931        final String modificationTime = getModificationTime(pathname);
2932        if (modificationTime != null) {
2933            final FTPFile file = new FTPFile();
2934            file.setName(pathname);
2935            file.setRawListing(modificationTime);
2936            file.setTimestamp(MLSxEntryParser.parseGMTdateTime(modificationTime));
2937            return file;
2938        }
2939        return null;
2940    }
2941
2942    /**
2943     * Merge two copystream listeners, either or both of which may be null.
2944     *
2945     * @param local the listener used by this class, may be null
2946     * @return a merged listener or a single listener or null
2947     * @since 3.0
2948     */
2949    private CopyStreamListener mergeListeners(final CopyStreamListener local) {
2950        if (local == null) {
2951            return copyStreamListener;
2952        }
2953        if (copyStreamListener == null) {
2954            return local;
2955        }
2956        // Both are non-null
2957        final CopyStreamAdapter merged = new CopyStreamAdapter();
2958        merged.addCopyStreamListener(local);
2959        merged.addCopyStreamListener(copyStreamListener);
2960        return merged;
2961    }
2962
2963    /**
2964     * Generate a directory listing for the current directory using the MLSD command.
2965     *
2966     * @return the array of file entries
2967     * @throws IOException on error
2968     * @since 3.0
2969     */
2970    public FTPFile[] mlistDir() throws IOException
2971    {
2972        return mlistDir(null);
2973    }
2974
2975    /**
2976     * Generate a directory listing using the MLSD command.
2977     *
2978     * @param pathname the directory name, may be {@code null}
2979     * @return the array of file entries
2980     * @throws IOException on error
2981     * @since 3.0
2982     */
2983    public FTPFile[] mlistDir(final String pathname) throws IOException {
2984        return initiateMListParsing(pathname).getFiles();
2985    }
2986
2987    /**
2988     * Generate a directory listing using the MLSD command.
2989     *
2990     * @param pathname the directory name, may be {@code null}
2991     * @param filter the filter to apply to the responses
2992     * @return the array of file entries
2993     * @throws IOException on error
2994     * @since 3.0
2995     */
2996    public FTPFile[] mlistDir(final String pathname, final FTPFileFilter filter) throws IOException {
2997        return initiateMListParsing(pathname).getFiles(filter);
2998    }
2999
3000    /**
3001     * Get file details using the MLST command
3002     *
3003     * @param pathname the file or directory to list, may be {@code null}
3004     * @return the file details, may be {@code null}
3005     * @throws IOException on error
3006     * @since 3.0
3007     */
3008    public FTPFile mlistFile(final String pathname) throws IOException
3009    {
3010        final boolean success = FTPReply.isPositiveCompletion(sendCommand(FTPCmd.MLST, pathname));
3011        if (success){
3012            String reply = getReplyString(1);
3013            // some FTP server reply not contains space before fact(s)
3014            if(reply.charAt(0) != ' ') { reply = " " + reply; }
3015            /* check the response makes sense.
3016             * Must have space before fact(s) and between fact(s) and file name
3017             * Fact(s) can be absent, so at least 3 chars are needed.
3018             */
3019            if (reply.length() < 3) {
3020                throw new MalformedServerReplyException("Invalid server reply (MLST): '" + reply + "'");
3021            }
3022            // some FTP server reply contains more than one space before fact(s)
3023            final String entry = reply.replaceAll("^\\s+", ""); // skip leading space for parser
3024            return MLSxEntryParser.parseEntry(entry);
3025        }
3026        return null;
3027    }
3028
3029    /**
3030     * Returns the pathname of the current working directory.
3031     *
3032     * @return The pathname of the current working directory.  If it cannot
3033     *         be obtained, returns null.
3034     * @throws FTPConnectionClosedException
3035     *      If the FTP server prematurely closes the connection as a result
3036     *      of the client being idle or some other reason causing the server
3037     *      to send FTP reply code 421.  This exception may be caught either
3038     *      as an IOException or independently as itself.
3039     * @throws IOException  If an I/O error occurs while either sending a
3040     *      command to the server or receiving a reply from the server.
3041     */
3042    public String printWorkingDirectory() throws IOException
3043    {
3044        if (pwd() != FTPReply.PATHNAME_CREATED) {
3045            return null;
3046        }
3047
3048        return parsePathname(_replyLines.get( _replyLines.size() - 1));
3049    }
3050
3051    /**
3052     * Reinitialize the FTP session.  Not all FTP servers support this
3053     * command, which issues the FTP REIN command.
3054     *
3055     * @return True if successfully completed, false if not.
3056     * @throws FTPConnectionClosedException
3057     *      If the FTP server prematurely closes the connection as a result
3058     *      of the client being idle or some other reason causing the server
3059     *      to send FTP reply code 421.  This exception may be caught either
3060     *      as an IOException or independently as itself.
3061     * @throws IOException  If an I/O error occurs while either sending a
3062     *      command to the server or receiving a reply from the server.
3063     * @since 3.4 (made public)
3064     */
3065    public boolean reinitialize() throws IOException
3066    {
3067        rein();
3068
3069        if (FTPReply.isPositiveCompletion(_replyCode) ||
3070                (FTPReply.isPositivePreliminary(_replyCode) &&
3071                        FTPReply.isPositiveCompletion(getReply())))
3072        {
3073
3074            initDefaults();
3075
3076            return true;
3077        }
3078
3079        return false;
3080    }
3081
3082    // For server to server transfers
3083    /**
3084     * Initiate a server to server file transfer.  This method tells the
3085     * server to which the client is connected to append to a given file on
3086     * the other server.  The other server must have had a
3087     * <code> remoteRetrieve </code> issued to it by another FTPClient.
3088     *
3089     * @param fileName  The name of the file to be appended to, or if the
3090     *        file does not exist, the name to call the file being stored.
3091     *
3092     * @return True if successfully completed, false if not.
3093     * @throws FTPConnectionClosedException
3094     *      If the FTP server prematurely closes the connection as a result
3095     *      of the client being idle or some other reason causing the server
3096     *      to send FTP reply code 421.  This exception may be caught either
3097     *      as an IOException or independently as itself.
3098     * @throws IOException  If an I/O error occurs while either sending a
3099     *      command to the server or receiving a reply from the server.
3100     */
3101    public boolean remoteAppend(final String fileName) throws IOException
3102    {
3103        if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
3104                dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) {
3105            return FTPReply.isPositivePreliminary(appe(fileName));
3106        }
3107        return false;
3108    }
3109
3110    /**
3111     * Initiate a server to server file transfer.  This method tells the
3112     * server to which the client is connected to retrieve a given file from
3113     * the other server.
3114     *
3115     * @param fileName  The name of the file to retrieve.
3116     * @return True if successfully completed, false if not.
3117     * @throws FTPConnectionClosedException
3118     *      If the FTP server prematurely closes the connection as a result
3119     *      of the client being idle or some other reason causing the server
3120     *      to send FTP reply code 421.  This exception may be caught either
3121     *      as an IOException or independently as itself.
3122     * @throws IOException  If an I/O error occurs while either sending a
3123     *      command to the server or receiving a reply from the server.
3124     */
3125    public boolean remoteRetrieve(final String fileName) throws IOException
3126    {
3127        if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
3128                dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) {
3129            return FTPReply.isPositivePreliminary(retr(fileName));
3130        }
3131        return false;
3132    }
3133
3134    /**
3135     * Initiate a server to server file transfer.  This method tells the
3136     * server to which the client is connected to store a file on
3137     * the other server using the given file name.  The other server must
3138     * have had a <code> remoteRetrieve </code> issued to it by another
3139     * FTPClient.
3140     *
3141     * @param fileName  The name to call the file that is to be stored.
3142     * @return True if successfully completed, false if not.
3143     * @throws FTPConnectionClosedException
3144     *      If the FTP server prematurely closes the connection as a result
3145     *      of the client being idle or some other reason causing the server
3146     *      to send FTP reply code 421.  This exception may be caught either
3147     *      as an IOException or independently as itself.
3148     * @throws IOException  If an I/O error occurs while either sending a
3149     *      command to the server or receiving a reply from the server.
3150     */
3151    public boolean remoteStore(final String fileName) throws IOException
3152    {
3153        if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
3154                dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) {
3155            return FTPReply.isPositivePreliminary(stor(fileName));
3156        }
3157        return false;
3158    }
3159
3160    /**
3161     * Initiate a server to server file transfer.  This method tells the
3162     * server to which the client is connected to store a file on
3163     * the other server using a unique file name.
3164     * The other server must have had a <code> remoteRetrieve </code> issued
3165     * to it by another FTPClient.  Many FTP servers require that a base
3166     * file name be given from which the unique file name can be derived.  For
3167     * those servers use the other version of <code> remoteStoreUnique</code>
3168     *
3169     * @return True if successfully completed, false if not.
3170     * @throws FTPConnectionClosedException
3171     *      If the FTP server prematurely closes the connection as a result
3172     *      of the client being idle or some other reason causing the server
3173     *      to send FTP reply code 421.  This exception may be caught either
3174     *      as an IOException or independently as itself.
3175     * @throws IOException  If an I/O error occurs while either sending a
3176     *      command to the server or receiving a reply from the server.
3177     */
3178    public boolean remoteStoreUnique() throws IOException
3179    {
3180        if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
3181                dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) {
3182            return FTPReply.isPositivePreliminary(stou());
3183        }
3184        return false;
3185    }
3186
3187    /**
3188     * Initiate a server to server file transfer.  This method tells the
3189     * server to which the client is connected to store a file on
3190     * the other server using a unique file name based on the given file name.
3191     * The other server must have had a <code> remoteRetrieve </code> issued
3192     * to it by another FTPClient.
3193     *
3194     * @param fileName  The name on which to base the file name of the file
3195     *                  that is to be stored.
3196     * @return True if successfully completed, false if not.
3197     * @throws FTPConnectionClosedException
3198     *      If the FTP server prematurely closes the connection as a result
3199     *      of the client being idle or some other reason causing the server
3200     *      to send FTP reply code 421.  This exception may be caught either
3201     *      as an IOException or independently as itself.
3202     * @throws IOException  If an I/O error occurs while either sending a
3203     *      command to the server or receiving a reply from the server.
3204     */
3205    public boolean remoteStoreUnique(final String fileName) throws IOException
3206    {
3207        if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
3208                dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) {
3209            return FTPReply.isPositivePreliminary(stou(fileName));
3210        }
3211        return false;
3212    }
3213
3214    /**
3215     * Removes a directory on the FTP server (if empty).
3216     *
3217     * @param pathname  The pathname of the directory to remove.
3218     * @return True if successfully completed, false if not.
3219     * @throws FTPConnectionClosedException
3220     *      If the FTP server prematurely closes the connection as a result
3221     *      of the client being idle or some other reason causing the server
3222     *      to send FTP reply code 421.  This exception may be caught either
3223     *      as an IOException or independently as itself.
3224     * @throws IOException  If an I/O error occurs while either sending a
3225     *      command to the server or receiving a reply from the server.
3226     */
3227    public boolean removeDirectory(final String pathname) throws IOException
3228    {
3229        return FTPReply.isPositiveCompletion(rmd(pathname));
3230    }
3231
3232    /**
3233     * Renames a remote file.
3234     *
3235     * @param from  The name of the remote file to rename.
3236     * @param to    The new name of the remote file.
3237     * @return True if successfully completed, false if not.
3238     * @throws FTPConnectionClosedException
3239     *      If the FTP server prematurely closes the connection as a result
3240     *      of the client being idle or some other reason causing the server
3241     *      to send FTP reply code 421.  This exception may be caught either
3242     *      as an IOException or independently as itself.
3243     * @throws IOException  If an I/O error occurs while either sending a
3244     *      command to the server or receiving a reply from the server.
3245     */
3246    public boolean rename(final String from, final String to) throws IOException
3247    {
3248        if (!FTPReply.isPositiveIntermediate(rnfr(from))) {
3249            return false;
3250        }
3251
3252        return FTPReply.isPositiveCompletion(rnto(to));
3253    }
3254
3255    /**
3256     * Restart a <code>STREAM_TRANSFER_MODE</code> file transfer starting
3257     * from the given offset.  This will only work on FTP servers supporting
3258     * the REST comand for the stream transfer mode.  However, most FTP
3259     * servers support this.  Any subsequent file transfer will start
3260     * reading or writing the remote file from the indicated offset.
3261     *
3262     * @param offset  The offset into the remote file at which to start the
3263     *           next file transfer.
3264     * @return True if successfully completed, false if not.
3265     * @throws FTPConnectionClosedException
3266     *      If the FTP server prematurely closes the connection as a result
3267     *      of the client being idle or some other reason causing the server
3268     *      to send FTP reply code 421.  This exception may be caught either
3269     *      as an IOException or independently as itself.
3270     * @throws IOException  If an I/O error occurs while either sending a
3271     *      command to the server or receiving a reply from the server.
3272     * @since 3.1 (changed from private to protected)
3273     */
3274    protected boolean restart(final long offset) throws IOException
3275    {
3276        restartOffset = 0;
3277        return FTPReply.isPositiveIntermediate(rest(Long.toString(offset)));
3278    }
3279
3280    /**
3281     * Retrieves a named file from the server and writes it to the given
3282     * OutputStream.  This method does NOT close the given OutputStream.
3283     * If the current file type is ASCII, line separators in the file are
3284     * converted to the local representation.
3285     * <p>
3286     * Note: if you have used {@link #setRestartOffset(long)},
3287     * the file data will start from the selected offset.
3288     * @param remote  The name of the remote file.
3289     * @param local   The local OutputStream to which to write the file.
3290     * @return True if successfully completed, false if not.
3291     * @throws FTPConnectionClosedException
3292     *      If the FTP server prematurely closes the connection as a result
3293     *      of the client being idle or some other reason causing the server
3294     *      to send FTP reply code 421.  This exception may be caught either
3295     *      as an IOException or independently as itself.
3296     * @throws org.apache.commons.net.io.CopyStreamException
3297     *      If an I/O error occurs while actually
3298     *      transferring the file.  The CopyStreamException allows you to
3299     *      determine the number of bytes transferred and the IOException
3300     *      causing the error.  This exception may be caught either
3301     *      as an IOException or independently as itself.
3302     * @throws IOException  If an I/O error occurs while either sending a
3303     *      command to the server or receiving a reply from the server.
3304     */
3305    public boolean retrieveFile(final String remote, final OutputStream local)
3306    throws IOException
3307    {
3308        return _retrieveFile(FTPCmd.RETR.getCommand(), remote, local);
3309    }
3310
3311    /**
3312     * Returns an InputStream from which a named file from the server
3313     * can be read.  If the current file type is ASCII, the returned
3314     * InputStream will convert line separators in the file to
3315     * the local representation.  You must close the InputStream when you
3316     * finish reading from it.  The InputStream itself will take care of
3317     * closing the parent data connection socket upon being closed.
3318     * <p>
3319     * <b>To finalize the file transfer you must call
3320     * {@link #completePendingCommand  completePendingCommand } and
3321     * check its return value to verify success.</b>
3322     * If this is not done, subsequent commands may behave unexpectedly.
3323     * <p>
3324     * Note: if you have used {@link #setRestartOffset(long)},
3325     * the file data will start from the selected offset.
3326     *
3327     * @param remote  The name of the remote file.
3328     * @return An InputStream from which the remote file can be read.  If
3329     *      the data connection cannot be opened (e.g., the file does not
3330     *      exist), null is returned (in which case you may check the reply
3331     *      code to determine the exact reason for failure).
3332     * @throws FTPConnectionClosedException
3333     *      If the FTP server prematurely closes the connection as a result
3334     *      of the client being idle or some other reason causing the server
3335     *      to send FTP reply code 421.  This exception may be caught either
3336     *      as an IOException or independently as itself.
3337     * @throws IOException  If an I/O error occurs while either sending a
3338     *      command to the server or receiving a reply from the server.
3339     */
3340    public InputStream retrieveFileStream(final String remote) throws IOException
3341    {
3342        return _retrieveFileStream(FTPCmd.RETR.getCommand(), remote);
3343    }
3344
3345
3346    /**
3347     * Sends a NOOP command to the FTP server.  This is useful for preventing
3348     * server timeouts.
3349     *
3350     * @return True if successfully completed, false if not.
3351     * @throws FTPConnectionClosedException
3352     *      If the FTP server prematurely closes the connection as a result
3353     *      of the client being idle or some other reason causing the server
3354     *      to send FTP reply code 421.  This exception may be caught either
3355     *      as an IOException or independently as itself.
3356     * @throws IOException  If an I/O error occurs while either sending a
3357     *      command to the server or receiving a reply from the server.
3358     */
3359    public boolean sendNoOp() throws IOException
3360    {
3361        return FTPReply.isPositiveCompletion(noop());
3362    }
3363
3364    /**
3365     * Send a site specific command.
3366     * @param arguments The site specific command and arguments.
3367     * @return True if successfully completed, false if not.
3368     * @throws FTPConnectionClosedException
3369     *      If the FTP server prematurely closes the connection as a result
3370     *      of the client being idle or some other reason causing the server
3371     *      to send FTP reply code 421.  This exception may be caught either
3372     *      as an IOException or independently as itself.
3373     * @throws IOException  If an I/O error occurs while either sending a
3374     *      command to the server or receiving a reply from the server.
3375     */
3376    public boolean sendSiteCommand(final String arguments) throws IOException
3377    {
3378        return FTPReply.isPositiveCompletion(site(arguments));
3379    }
3380
3381    /**
3382     * Set the external IP address in active mode.
3383     * Useful when there are multiple network cards.
3384     *
3385     * @param ipAddress The external IP address of this machine.
3386     * @throws UnknownHostException if the ipAddress cannot be resolved
3387     * @since 2.2
3388     */
3389    public void setActiveExternalIPAddress(final String ipAddress) throws UnknownHostException
3390    {
3391        this.activeExternalHost = InetAddress.getByName(ipAddress);
3392    }
3393
3394    /**
3395     * Set the client side port range in active mode.
3396     *
3397     * @param minPort The lowest available port (inclusive).
3398     * @param maxPort The highest available port (inclusive).
3399     * @since 2.2
3400     */
3401    public void setActivePortRange(final int minPort, final int maxPort)
3402    {
3403        this.activeMinPort = minPort;
3404        this.activeMaxPort = maxPort;
3405    }
3406
3407    /**
3408     * Enables or disables automatic server encoding detection (only UTF-8 supported).
3409     * <p>
3410     * Does not affect existing connections; must be invoked before a connection is established.
3411     *
3412     * @param autodetect If true, automatic server encoding detection will be enabled.
3413     */
3414    public void setAutodetectUTF8(final boolean autodetect)
3415    {
3416        autodetectEncoding = autodetect;
3417    }
3418
3419    /**
3420     * Set the internal buffer size for buffered data streams.
3421     *
3422     * @param bufSize The size of the buffer. Use a non-positive value to use the default.
3423     */
3424    public void setBufferSize(final int bufSize) {
3425        bufferSize = bufSize;
3426    }
3427
3428    /**
3429     * Sets how long to wait for control keep-alive message replies.
3430     *
3431     * @param timeoutMillis number of milliseconds to wait (defaults to 1000)
3432     * @since 3.0
3433     * @see #setControlKeepAliveTimeout(long)
3434     */
3435    public void setControlKeepAliveReplyTimeout(final int timeoutMillis) {
3436        controlKeepAliveReplyTimeoutMillis = timeoutMillis;
3437    }
3438
3439    /**
3440     * Set the time to wait between sending control connection keepalive messages
3441     * when processing file upload or download.
3442     * <p>
3443     * See the class Javadoc section "Control channel keep-alive feature:"
3444     *
3445     * @param controlIdleSeconds the wait (in seconds) between keepalive messages. Zero (or less) disables.
3446     * @since 3.0
3447     * @see #setControlKeepAliveReplyTimeout(int)
3448     */
3449    public void setControlKeepAliveTimeout(final long controlIdleSeconds){
3450        controlKeepAliveTimeoutMillis = controlIdleSeconds * 1000;
3451    }
3452
3453    /**
3454     * Set the listener to be used when performing store/retrieve operations.
3455     * The default value (if not set) is {@code null}.
3456     *
3457     * @param listener to be used, may be {@code null} to disable
3458     * @since 3.0
3459     */
3460    public void setCopyStreamListener(final CopyStreamListener listener){
3461        copyStreamListener = listener;
3462    }
3463
3464    /**
3465     * Sets the timeout in milliseconds to use when reading from the
3466     * data connection.  This timeout will be set immediately after
3467     * opening the data connection, provided that the value is &ge; 0.
3468     * <p>
3469     * <b>Note:</b> the timeout will also be applied when calling accept()
3470     * whilst establishing an active local data connection.
3471     * @param  timeoutMillis The default timeout in milliseconds that is used when
3472     *        opening a data connection socket. The value 0 means an infinite timeout.
3473     */
3474    public void setDataTimeout(final int timeoutMillis)
3475    {
3476        dataTimeoutMillis = timeoutMillis;
3477    }
3478
3479    /**
3480     * Sets the file structure.  The default structure is
3481     * <code> FTP.FILE_STRUCTURE </code> if this method is never called
3482     * or if a connect method is called.
3483     *
3484     * @param structure  The structure of the file (one of the FTP class
3485     *         <code>_STRUCTURE</code> constants).
3486     * @return True if successfully completed, false if not.
3487     * @throws FTPConnectionClosedException
3488     *      If the FTP server prematurely closes the connection as a result
3489     *      of the client being idle or some other reason causing the server
3490     *      to send FTP reply code 421.  This exception may be caught either
3491     *      as an IOException or independently as itself.
3492     * @throws IOException  If an I/O error occurs while either sending a
3493     *      command to the server or receiving a reply from the server.
3494     */
3495    public boolean setFileStructure(final int structure) throws IOException
3496    {
3497        if (FTPReply.isPositiveCompletion(stru(structure)))
3498        {
3499            fileStructure = structure;
3500            return true;
3501        }
3502        return false;
3503    }
3504
3505    /**
3506     * Sets the transfer mode.  The default transfer mode
3507     * <code> FTP.STREAM_TRANSFER_MODE </code> if this method is never called
3508     * or if a connect method is called.
3509     *
3510     * @param mode  The new transfer mode to use (one of the FTP class
3511     *         <code>_TRANSFER_MODE</code> constants).
3512     * @return True if successfully completed, false if not.
3513     * @throws FTPConnectionClosedException
3514     *      If the FTP server prematurely closes the connection as a result
3515     *      of the client being idle or some other reason causing the server
3516     *      to send FTP reply code 421.  This exception may be caught either
3517     *      as an IOException or independently as itself.
3518     * @throws IOException  If an I/O error occurs while either sending a
3519     *      command to the server or receiving a reply from the server.
3520     */
3521    public boolean setFileTransferMode(final int mode) throws IOException
3522    {
3523        if (FTPReply.isPositiveCompletion(mode(mode)))
3524        {
3525            fileTransferMode = mode;
3526            return true;
3527        }
3528        return false;
3529    }
3530
3531    /**
3532     * Sets the file type to be transferred.  This should be one of
3533     * <code> FTP.ASCII_FILE_TYPE </code>, <code> FTP.BINARY_FILE_TYPE</code>,
3534     * etc.  The file type only needs to be set when you want to change the
3535     * type.  After changing it, the new type stays in effect until you change
3536     * it again.  The default file type is <code> FTP.ASCII_FILE_TYPE </code>
3537     * if this method is never called.
3538     * <br>
3539     * The server default is supposed to be ASCII (see RFC 959), however many
3540     * ftp servers default to BINARY. <b>To ensure correct operation with all servers,
3541     * always specify the appropriate file type after connecting to the server.</b>
3542     * <br>
3543     * <p>
3544     * <b>N.B.</b> currently calling any connect method will reset the type to
3545     * FTP.ASCII_FILE_TYPE.
3546     * @param fileType The <code> _FILE_TYPE </code> constant indicating the
3547     *                 type of file.
3548     * @return True if successfully completed, false if not.
3549     * @throws FTPConnectionClosedException
3550     *      If the FTP server prematurely closes the connection as a result
3551     *      of the client being idle or some other reason causing the server
3552     *      to send FTP reply code 421.  This exception may be caught either
3553     *      as an IOException or independently as itself.
3554     * @throws IOException  If an I/O error occurs while either sending a
3555     *      command to the server or receiving a reply from the server.
3556     */
3557    public boolean setFileType(final int fileType) throws IOException
3558    {
3559        if (FTPReply.isPositiveCompletion(type(fileType)))
3560        {
3561            this.fileType = fileType;
3562            this.fileFormat = FTP.NON_PRINT_TEXT_FORMAT;
3563            return true;
3564        }
3565        return false;
3566    }
3567
3568    /**
3569     * Sets the file type to be transferred and the format.  The type should be
3570     * one of  <code> FTP.ASCII_FILE_TYPE </code>,
3571     * <code> FTP.BINARY_FILE_TYPE </code>, etc.  The file type only needs to
3572     * be set when you want to change the type.  After changing it, the new
3573     * type stays in effect until you change it again.  The default file type
3574     * is <code> FTP.ASCII_FILE_TYPE </code> if this method is never called.
3575     * <br>
3576     * The server default is supposed to be ASCII (see RFC 959), however many
3577     * ftp servers default to BINARY. <b>To ensure correct operation with all servers,
3578     * always specify the appropriate file type after connecting to the server.</b>
3579     * <br>
3580     * The format should be one of the FTP class <code> TEXT_FORMAT </code>
3581     * constants, or if the type is <code> FTP.LOCAL_FILE_TYPE </code>, the
3582     * format should be the byte size for that type.  The default format
3583     * is <code> FTP.NON_PRINT_TEXT_FORMAT </code> if this method is never
3584     * called.
3585     * <p>
3586     * <b>N.B.</b> currently calling any connect method will reset the type to
3587     * FTP.ASCII_FILE_TYPE and the formatOrByteSize to FTP.NON_PRINT_TEXT_FORMAT.
3588     *
3589     * @param fileType The <code> _FILE_TYPE </code> constant indicating the
3590     *                 type of file.
3591     * @param formatOrByteSize  The format of the file (one of the
3592     *              <code>_FORMAT</code> constants.  In the case of
3593     *              <code>LOCAL_FILE_TYPE</code>, the byte size.
3594     *
3595     * @return True if successfully completed, false if not.
3596     * @throws FTPConnectionClosedException
3597     *      If the FTP server prematurely closes the connection as a result
3598     *      of the client being idle or some other reason causing the server
3599     *      to send FTP reply code 421.  This exception may be caught either
3600     *      as an IOException or independently as itself.
3601     * @throws IOException  If an I/O error occurs while either sending a
3602     *      command to the server or receiving a reply from the server.
3603     */
3604    public boolean setFileType(final int fileType, final int formatOrByteSize)
3605    throws IOException
3606    {
3607        if (FTPReply.isPositiveCompletion(type(fileType, formatOrByteSize)))
3608        {
3609            this.fileType = fileType;
3610            this.fileFormat = formatOrByteSize;
3611            return true;
3612        }
3613        return false;
3614    }
3615
3616    /**
3617     * You can set this to true if you would like to get hidden files when {@link #listFiles} too.
3618     * A <code>LIST -a</code> will be issued to the ftp server.
3619     * It depends on your ftp server if you need to call this method, also dont expect to get rid
3620     * of hidden files if you call this method with "false".
3621     *
3622     * @param listHiddenFiles true if hidden files should be listed
3623     * @since 2.0
3624     */
3625    public void setListHiddenFiles(final boolean listHiddenFiles) {
3626        this.listHiddenFiles = listHiddenFiles;
3627    }
3628
3629    /**
3630     * Issue the FTP MFMT command (not supported by all servers) which sets the last
3631     * modified time of a file.
3632     *
3633     * The timestamp should be in the form <code>YYYYMMDDhhmmss</code>. It should also
3634     * be in GMT, but not all servers honor this.
3635     *
3636     * An FTP server would indicate its support of this feature by including "MFMT"
3637     * in its response to the FEAT command, which may be retrieved by FTPClient.features()
3638     *
3639     * @param pathname The file path for which last modified time is to be changed.
3640     * @param timeval The timestamp to set to, in <code>YYYYMMDDhhmmss</code> format.
3641     * @return true if successfully set, false if not
3642     * @throws IOException if an I/O error occurs.
3643     * @since 2.2
3644     * @see <a href="http://tools.ietf.org/html/draft-somers-ftp-mfxx-04">http://tools.ietf.org/html/draft-somers-ftp-mfxx-04</a>
3645     */
3646    public boolean setModificationTime(final String pathname, final String timeval) throws IOException {
3647        return (FTPReply.isPositiveCompletion(mfmt(pathname, timeval)));
3648    }
3649
3650    /**
3651     * set the factory used for parser creation to the supplied factory object.
3652     *
3653     * @param parserFactory
3654     *               factory object used to create FTPFileEntryParsers
3655     *
3656     * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
3657     * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
3658     */
3659    public void setParserFactory(final FTPFileEntryParserFactory parserFactory) {
3660        this.parserFactory = parserFactory;
3661    }
3662
3663    /**
3664     * Set the local IP address to use in passive mode.
3665     * Useful when there are multiple network cards.
3666     *
3667     * @param inetAddress The local IP address of this machine.
3668     */
3669    public void setPassiveLocalIPAddress(final InetAddress inetAddress)
3670    {
3671        this.passiveLocalHost = inetAddress;
3672    }
3673
3674    /**
3675     * Set the local IP address to use in passive mode.
3676     * Useful when there are multiple network cards.
3677     *
3678     * @param ipAddress The local IP address of this machine.
3679     * @throws UnknownHostException if the ipAddress cannot be resolved
3680     */
3681    public void setPassiveLocalIPAddress(final String ipAddress) throws UnknownHostException
3682    {
3683        this.passiveLocalHost = InetAddress.getByName(ipAddress);
3684    }
3685
3686    /**
3687     * Enables or disables passive mode NAT workaround.
3688     * If enabled, a site-local PASV mode reply address will be replaced with the
3689     * remote host address to which the PASV mode request was sent
3690     * (unless that is also a site local address).
3691     * This gets around the problem that some NAT boxes may change the
3692     * reply.
3693     *
3694     * The default is true, i.e. site-local replies are replaced.
3695     * @param enabled true to enable replacing internal IP's in passive
3696     * mode.
3697     * @deprecated (3.6) use {@link #setPassiveNatWorkaroundStrategy(HostnameResolver)} instead
3698     */
3699    @Deprecated
3700    public void setPassiveNatWorkaround(final boolean enabled) {
3701        if (enabled) {
3702            this.passiveNatWorkaroundStrategy = new NatServerResolverImpl(this);
3703        } else {
3704            this.passiveNatWorkaroundStrategy = null;
3705        }
3706    }
3707
3708    /**
3709     * Set the workaround strategy to replace the PASV mode reply addresses.
3710     * This gets around the problem that some NAT boxes may change the reply.
3711     *
3712     * The default implementation is {@code NatServerResolverImpl}, i.e. site-local
3713     * replies are replaced.
3714     * @param resolver strategy to replace internal IP's in passive mode
3715     * or null to disable the workaround (i.e. use PASV mode reply address.)
3716     * @since 3.6
3717     */
3718    public void setPassiveNatWorkaroundStrategy(final HostnameResolver resolver) {
3719        this.passiveNatWorkaroundStrategy = resolver;
3720    }
3721
3722    /**
3723     * Sets the value to be used for the data socket SO_RCVBUF option.
3724     * If the value is positive, the option will be set when the data socket has been created.
3725     *
3726     * @param bufSize The size of the buffer, zero or negative means the value is ignored.
3727     * @since 3.3
3728     */
3729    public void setReceieveDataSocketBufferSize(final int bufSize) {
3730        receiveDataSocketBufferSize = bufSize;
3731    }
3732
3733    /**
3734     * Enable or disable verification that the remote host taking part
3735     * of a data connection is the same as the host to which the control
3736     * connection is attached.  The default is for verification to be
3737     * enabled.  You may set this value at any time, whether the
3738     * FTPClient is currently connected or not.
3739     *
3740     * @param enable True to enable verification, false to disable verification.
3741     */
3742    public void setRemoteVerificationEnabled(final boolean enable)
3743    {
3744        remoteVerificationEnabled = enable;
3745    }
3746
3747    /**
3748     * Set the external IP address to report in EPRT/PORT commands in active mode.
3749     * Useful when there are multiple network cards.
3750     *
3751     * @param ipAddress The external IP address of this machine.
3752     * @throws UnknownHostException if the ipAddress cannot be resolved
3753     * @since 3.1
3754     * @see #getReportHostAddress()
3755     */
3756    public void setReportActiveExternalIPAddress(final String ipAddress) throws UnknownHostException
3757    {
3758        this.reportActiveExternalHost = InetAddress.getByName(ipAddress);
3759    }
3760
3761    /**
3762     * Sets the restart offset for file transfers.
3763     * <p>
3764     * The restart command is not sent to the server immediately.
3765     * It is sent when a data connection is created as part of a
3766     * subsequent command.
3767     * The restart marker is reset to zero after use.
3768     * </p>
3769     * <p>
3770     * <b>Note: This method should only be invoked immediately prior to
3771     * the transfer to which it applies.</b>
3772     *
3773     * @param offset  The offset into the remote file at which to start the
3774     *           next file transfer.  This must be a value greater than or
3775     *           equal to zero.
3776     */
3777    public void setRestartOffset(final long offset)
3778    {
3779        if (offset >= 0) {
3780            restartOffset = offset;
3781        }
3782    }
3783
3784    /**
3785     * Sets the value to be used for the data socket SO_SNDBUF option.
3786     * If the value is positive, the option will be set when the data socket has been created.
3787     *
3788     * @param bufSize The size of the buffer, zero or negative means the value is ignored.
3789      * @since 3.3
3790    */
3791    public void setSendDataSocketBufferSize(final int bufSize) {
3792        sendDataSocketBufferSize = bufSize;
3793    }
3794
3795    /**
3796     * Set whether to use EPSV with IPv4.
3797     * Might be worth enabling in some circumstances.
3798     *
3799     * For example, when using IPv4 with NAT it
3800     * may work with some rare configurations.
3801     * E.g. if FTP server has a static PASV address (external network)
3802     * and the client is coming from another internal network.
3803     * In that case the data connection after PASV command would fail,
3804     * while EPSV would make the client succeed by taking just the port.
3805     *
3806     * @param selected value to set.
3807     * @since 2.2
3808     */
3809    public void setUseEPSVwithIPv4(final boolean selected) {
3810        this.useEPSVwithIPv4 = selected;
3811    }
3812
3813    private boolean storeFile(final FTPCmd command, final String remote, final InputStream local)
3814    throws IOException
3815    {
3816        return _storeFile(command.getCommand(), remote, local);
3817    }
3818
3819    /**
3820     * Stores a file on the server using the given name and taking input
3821     * from the given InputStream.  This method does NOT close the given
3822     * InputStream.  If the current file type is ASCII, line separators in
3823     * the file are transparently converted to the NETASCII format (i.e.,
3824     * you should not attempt to create a special InputStream to do this).
3825     *
3826     * @param remote  The name to give the remote file.
3827     * @param local   The local InputStream from which to read the file.
3828     * @return True if successfully completed, false if not.
3829     * @throws FTPConnectionClosedException
3830     *      If the FTP server prematurely closes the connection as a result
3831     *      of the client being idle or some other reason causing the server
3832     *      to send FTP reply code 421.  This exception may be caught either
3833     *      as an IOException or independently as itself.
3834     * @throws org.apache.commons.net.io.CopyStreamException
3835     *      If an I/O error occurs while actually
3836     *      transferring the file.  The CopyStreamException allows you to
3837     *      determine the number of bytes transferred and the IOException
3838     *      causing the error.  This exception may be caught either
3839     *      as an IOException or independently as itself.
3840     * @throws IOException  If an I/O error occurs while either sending a
3841     *      command to the server or receiving a reply from the server.
3842     */
3843    public boolean storeFile(final String remote, final InputStream local)
3844    throws IOException
3845    {
3846        return storeFile(FTPCmd.STOR, remote, local);
3847    }
3848
3849    private OutputStream storeFileStream(final FTPCmd command, final String remote)
3850    throws IOException
3851    {
3852        return _storeFileStream(command.getCommand(), remote);
3853    }
3854
3855    /**
3856     * Returns an OutputStream through which data can be written to store
3857     * a file on the server using the given name.  If the current file type
3858     * is ASCII, the returned OutputStream will convert line separators in
3859     * the file to the NETASCII format  (i.e., you should not attempt to
3860     * create a special OutputStream to do this).  You must close the
3861     * OutputStream when you finish writing to it.  The OutputStream itself
3862     * will take care of closing the parent data connection socket upon being
3863     * closed.
3864     * <p>
3865     * <b>To finalize the file transfer you must call
3866     * {@link #completePendingCommand  completePendingCommand } and
3867     * check its return value to verify success.</b>
3868     * If this is not done, subsequent commands may behave unexpectedly.
3869     *
3870     * @param remote  The name to give the remote file.
3871     * @return An OutputStream through which the remote file can be written.  If
3872     *      the data connection cannot be opened (e.g., the file does not
3873     *      exist), null is returned (in which case you may check the reply
3874     *      code to determine the exact reason for failure).
3875     * @throws FTPConnectionClosedException
3876     *      If the FTP server prematurely closes the connection as a result
3877     *      of the client being idle or some other reason causing the server
3878     *      to send FTP reply code 421.  This exception may be caught either
3879     *      as an IOException or independently as itself.
3880     * @throws IOException  If an I/O error occurs while either sending a
3881     *      command to the server or receiving a reply from the server.
3882     */
3883    public OutputStream storeFileStream(final String remote) throws IOException
3884    {
3885        return storeFileStream(FTPCmd.STOR, remote);
3886    }
3887
3888    /**
3889     * Stores a file on the server using a unique name assigned by the
3890     * server and taking input from the given InputStream.  This method does
3891     * NOT close the given
3892     * InputStream.  If the current file type is ASCII, line separators in
3893     * the file are transparently converted to the NETASCII format (i.e.,
3894     * you should not attempt to create a special InputStream to do this).
3895     *
3896     * @param local   The local InputStream from which to read the file.
3897     * @return True if successfully completed, false if not.
3898     * @throws FTPConnectionClosedException
3899     *      If the FTP server prematurely closes the connection as a result
3900     *      of the client being idle or some other reason causing the server
3901     *      to send FTP reply code 421.  This exception may be caught either
3902     *      as an IOException or independently as itself.
3903     * @throws org.apache.commons.net.io.CopyStreamException
3904     *      If an I/O error occurs while actually
3905     *      transferring the file.  The CopyStreamException allows you to
3906     *      determine the number of bytes transferred and the IOException
3907     *      causing the error.  This exception may be caught either
3908     *      as an IOException or independently as itself.
3909     * @throws IOException  If an I/O error occurs while either sending a
3910     *      command to the server or receiving a reply from the server.
3911     */
3912    public boolean storeUniqueFile(final InputStream local) throws IOException
3913    {
3914        return storeFile(FTPCmd.STOU, null, local);
3915    }
3916
3917    /**
3918     * Stores a file on the server using a unique name derived from the
3919     * given name and taking input
3920     * from the given InputStream.  This method does NOT close the given
3921     * InputStream.  If the current file type is ASCII, line separators in
3922     * the file are transparently converted to the NETASCII format (i.e.,
3923     * you should not attempt to create a special InputStream to do this).
3924     *
3925     * @param remote  The name on which to base the unique name given to
3926     *                the remote file.
3927     * @param local   The local InputStream from which to read the file.
3928     * @return True if successfully completed, false if not.
3929     * @throws FTPConnectionClosedException
3930     *      If the FTP server prematurely closes the connection as a result
3931     *      of the client being idle or some other reason causing the server
3932     *      to send FTP reply code 421.  This exception may be caught either
3933     *      as an IOException or independently as itself.
3934     * @throws org.apache.commons.net.io.CopyStreamException
3935     *      If an I/O error occurs while actually
3936     *      transferring the file.  The CopyStreamException allows you to
3937     *      determine the number of bytes transferred and the IOException
3938     *      causing the error.  This exception may be caught either
3939     *      as an IOException or independently as itself.
3940     * @throws IOException  If an I/O error occurs while either sending a
3941     *      command to the server or receiving a reply from the server.
3942     */
3943    public boolean storeUniqueFile(final String remote, final InputStream local)
3944    throws IOException
3945    {
3946        return storeFile(FTPCmd.STOU, remote, local);
3947    }
3948
3949    /**
3950     * Returns an OutputStream through which data can be written to store
3951     * a file on the server using a unique name assigned by the server.
3952     * If the current file type
3953     * is ASCII, the returned OutputStream will convert line separators in
3954     * the file to the NETASCII format  (i.e., you should not attempt to
3955     * create a special OutputStream to do this).  You must close the
3956     * OutputStream when you finish writing to it.  The OutputStream itself
3957     * will take care of closing the parent data connection socket upon being
3958     * closed.
3959     * <p>
3960     * <b>To finalize the file transfer you must call
3961     * {@link #completePendingCommand  completePendingCommand } and
3962     * check its return value to verify success.</b>
3963     * If this is not done, subsequent commands may behave unexpectedly.
3964     *
3965     * @return An OutputStream through which the remote file can be written.  If
3966     *      the data connection cannot be opened (e.g., the file does not
3967     *      exist), null is returned (in which case you may check the reply
3968     *      code to determine the exact reason for failure).
3969     * @throws FTPConnectionClosedException
3970     *      If the FTP server prematurely closes the connection as a result
3971     *      of the client being idle or some other reason causing the server
3972     *      to send FTP reply code 421.  This exception may be caught either
3973     *      as an IOException or independently as itself.
3974     * @throws IOException  If an I/O error occurs while either sending a
3975     *      command to the server or receiving a reply from the server.
3976     */
3977    public OutputStream storeUniqueFileStream() throws IOException
3978    {
3979        return storeFileStream(FTPCmd.STOU, null);
3980    }
3981
3982    /**
3983     * Returns an OutputStream through which data can be written to store
3984     * a file on the server using a unique name derived from the given name.
3985     * If the current file type
3986     * is ASCII, the returned OutputStream will convert line separators in
3987     * the file to the NETASCII format  (i.e., you should not attempt to
3988     * create a special OutputStream to do this).  You must close the
3989     * OutputStream when you finish writing to it.  The OutputStream itself
3990     * will take care of closing the parent data connection socket upon being
3991     * closed.
3992     * <p>
3993     * <b>To finalize the file transfer you must call
3994     * {@link #completePendingCommand  completePendingCommand } and
3995     * check its return value to verify success.</b>
3996     * If this is not done, subsequent commands may behave unexpectedly.
3997     *
3998     * @param remote  The name on which to base the unique name given to
3999     *                the remote file.
4000     * @return An OutputStream through which the remote file can be written.  If
4001     *      the data connection cannot be opened (e.g., the file does not
4002     *      exist), null is returned (in which case you may check the reply
4003     *      code to determine the exact reason for failure).
4004     * @throws FTPConnectionClosedException
4005     *      If the FTP server prematurely closes the connection as a result
4006     *      of the client being idle or some other reason causing the server
4007     *      to send FTP reply code 421.  This exception may be caught either
4008     *      as an IOException or independently as itself.
4009     * @throws IOException  If an I/O error occurs while either sending a
4010     *      command to the server or receiving a reply from the server.
4011     */
4012    public OutputStream storeUniqueFileStream(final String remote) throws IOException
4013    {
4014        return storeFileStream(FTPCmd.STOU, remote);
4015    }
4016
4017    /**
4018     * Issue the FTP SMNT command.
4019     *
4020     * @param pathname The pathname to mount.
4021     * @return True if successfully completed, false if not.
4022     * @throws FTPConnectionClosedException
4023     *      If the FTP server prematurely closes the connection as a result
4024     *      of the client being idle or some other reason causing the server
4025     *      to send FTP reply code 421.  This exception may be caught either
4026     *      as an IOException or independently as itself.
4027     * @throws IOException  If an I/O error occurs while either sending a
4028     *      command to the server or receiving a reply from the server.
4029     */
4030    public boolean structureMount(final String pathname) throws IOException
4031    {
4032        return FTPReply.isPositiveCompletion(smnt(pathname));
4033    }
4034}