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