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