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