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