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