    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}