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