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; */