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