001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.net.ftp;
019import java.io.BufferedInputStream;
020import java.io.BufferedOutputStream;
021import java.io.BufferedReader;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.InputStreamReader;
025import java.io.OutputStream;
026import java.net.InetAddress;
027import java.net.ServerSocket;
028import java.net.Socket;
029import java.util.ArrayList;
030
031import org.apache.commons.net.MalformedServerReplyException;
032import org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory;
033import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory;
034import org.apache.commons.net.ftp.parser.ParserInitializationException;
035import org.apache.commons.net.io.CopyStreamEvent;
036import org.apache.commons.net.io.CopyStreamException;
037import org.apache.commons.net.io.FromNetASCIIInputStream;
038import org.apache.commons.net.io.ToNetASCIIOutputStream;
039import org.apache.commons.net.io.Util;
040
041/***
042 * FTPClient encapsulates all the functionality necessary to store and
043 * retrieve files from an FTP server.  This class takes care of all
044 * low level details of interacting with an FTP server and provides
045 * a convenient higher level interface.  As with all classes derived
046 * from {@link org.apache.commons.net.SocketClient},
047 * you must first connect to the server with
048 * {@link org.apache.commons.net.SocketClient#connect  connect }
049 * before doing anything, and finally
050 * {@link org.apache.commons.net.SocketClient#disconnect  disconnect }
051 * after you're completely finished interacting with the server.
052 * Then you need to check the FTP reply code to see if the connection
053 * was successful.  For example:
054 * <pre>
055 *    boolean error = false;
056 *    try {
057 *      int reply;
058 *      ftp.connect("ftp.foobar.com");
059 *      System.out.println("Connected to " + server + ".");
060 *      System.out.print(ftp.getReplyString());
061 *
062 *      // After connection attempt, you should check the reply code to verify
063 *      // success.
064 *      reply = ftp.getReplyCode();
065 *
066 *      if(!FTPReply.isPositiveCompletion(reply)) {
067 *        ftp.disconnect();
068 *        System.err.println("FTP server refused connection.");
069 *        System.exit(1);
070 *      }
071 *      ... // transfer files
072 *      ftp.logout();
073 *    } catch(IOException e) {
074 *      error = true;
075 *      e.printStackTrace();
076 *    } finally {
077 *      if(ftp.isConnected()) {
078 *        try {
079 *          ftp.disconnect();
080 *        } catch(IOException ioe) {
081 *          // do nothing
082 *        }
083 *      }
084 *      System.exit(error ? 1 : 0);
085 *    }
086 * </pre>
087 * <p>
088 * Immediately after connecting is the only real time you need to check the
089 * reply code (because connect is of type void).  The convention for all the
090 * FTP command methods in FTPClient is such that they either return a
091 * boolean value or some other value.
092 * The boolean methods return true on a successful completion reply from
093 * the FTP server and false on a reply resulting in an error condition or
094 * failure.  The methods returning a value other than boolean return a value
095 * containing the higher level data produced by the FTP command, or null if a
096 * reply resulted in an error condition or failure.  If you want to access
097 * the exact FTP reply code causing a success or failure, you must call
098 * {@link org.apache.commons.net.ftp.FTP#getReplyCode  getReplyCode } after
099 * a success or failure.
100 * <p>
101 * The default settings for FTPClient are for it to use
102 * <code> FTP.ASCII_FILE_TYPE </code>,
103 * <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
104 * <code> FTP.STREAM_TRANSFER_MODE </code>, and
105 * <code> FTP.FILE_STRUCTURE </code>.  The only file types directly supported
106 * are <code> FTP.ASCII_FILE_TYPE </code> and
107 * <code> FTP.BINARY_FILE_TYPE </code>.  Because there are at least 4
108 * different EBCDIC encodings, we have opted not to provide direct support
109 * for EBCDIC.  To transfer EBCDIC and other unsupported file types you
110 * must create your own filter InputStreams and OutputStreams and wrap
111 * them around the streams returned or required by the FTPClient methods.
112 * FTPClient uses the {@link ToNetASCIIOutputStream NetASCII}  
113 * filter streams to provide transparent handling of ASCII files.  We will 
114 * consider incorporating EBCDIC support if there is enough demand.
115 * <p>
116 * <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
117 * <code> FTP.STREAM_TRANSFER_MODE </code>, and
118 * <code> FTP.FILE_STRUCTURE </code> are the only supported formats,
119 * transfer modes, and file structures.
120 * <p>
121 * Because the handling of sockets on different platforms can differ
122 * significantly, the FTPClient automatically issues a new PORT command
123 * prior to every transfer requiring that the server connect to the client's
124 * data port.  This ensures identical problem-free behavior on Windows, Unix,
125 * and Macintosh platforms.  Additionally, it relieves programmers from
126 * having to issue the PORT command themselves and dealing with platform
127 * dependent issues.
128 * <p>
129 * Additionally, for security purposes, all data connections to the
130 * client are verified to ensure that they originated from the intended
131 * party (host and port).  If a data connection is initiated by an unexpected
132 * party, the command will close the socket and throw an IOException.  You
133 * may disable this behavior with
134 * {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()}.
135 * <p>
136 * You should keep in mind that the FTP server may choose to prematurely
137 * close a connection if the client has been idle for longer than a
138 * given time period (usually 900 seconds).  The FTPClient class will detect a
139 * premature FTP server connection closing when it receives a
140 * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE }
141 *  response to a command.
142 * When that occurs, the FTP class method encountering that reply will throw
143 * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException}
144 * .
145 * <code>FTPConnectionClosedException</code>
146 * is a subclass of <code> IOException </code> and therefore need not be
147 * caught separately, but if you are going to catch it separately, its
148 * catch block must appear before the more general <code> IOException </code>
149 * catch block.  When you encounter an
150 * {@link org.apache.commons.net.ftp.FTPConnectionClosedException}
151 * , you must disconnect the connection with
152 * {@link #disconnect  disconnect() } to properly clean up the
153 * system resources used by FTPClient.  Before disconnecting, you may check the
154 * last reply code and text with
155 * {@link org.apache.commons.net.ftp.FTP#getReplyCode  getReplyCode },
156 * {@link org.apache.commons.net.ftp.FTP#getReplyString  getReplyString },
157 * and
158 * {@link org.apache.commons.net.ftp.FTP#getReplyStrings  getReplyStrings}.
159 * You may avoid server disconnections while the client is idle by
160 * periodicaly sending NOOP commands to the server.
161 * <p>
162 * Rather than list it separately for each method, we mention here that
163 * every method communicating with the server and throwing an IOException
164 * can also throw a
165 * {@link org.apache.commons.net.MalformedServerReplyException}
166 * , which is a subclass
167 * of IOException.  A MalformedServerReplyException will be thrown when
168 * the reply received from the server deviates enough from the protocol
169 * specification that it cannot be interpreted in a useful manner despite
170 * attempts to be as lenient as possible.
171 * <p>
172 * Listing API Examples
173 * Both paged and unpaged examples of directory listings are available,
174 * as follows:
175 * <p>
176 * Unpaged (whole list) access, using a parser accessible by auto-detect:
177 * <pre>
178 *    FTPClient f=FTPClient();
179 *    f.connect(server);
180 *    f.login(username, password);
181 *    FTPFile[] files = listFiles(directory);
182 * </pre>
183 * <p>
184 * Paged access, using a parser not accessible by auto-detect.  The class
185 * defined in the first parameter of initateListParsing should be derived
186 * from org.apache.commons.net.FTPFileEntryParser:
187 * <pre>
188 *    FTPClient f=FTPClient();
189 *    f.connect(server);
190 *    f.login(username, password);
191 *    FTPListParseEngine engine =
192 *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
193 *
194 *    while (engine.hasNext()) {
195 *       FTPFile[] files = engine.getNext(25);  // "page size" you want
196 *       //do whatever you want with these files, display them, etc.
197 *       //expensive FTPFile objects not created until needed.
198 *    }
199 * </pre>
200 * <p>
201 * Paged access, using a parser accessible by auto-detect:
202 * <pre>
203 *    FTPClient f=FTPClient();
204 *    f.connect(server);
205 *    f.login(username, password);
206 *    FTPListParseEngine engine = f.initiateListParsing(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 * For examples of using FTPClient on servers whose directory listings 
216 * <ul> 
217 * <li>use languages other than English</li>
218 * <li>use date formats other than the American English "standard" <code>MM d yyyy</code></li>
219 * <li>are in different timezones and you need accurate timestamps for dependency checking 
220 *     as in Ant</li>
221 * </ul>see {@link  FTPClientConfig  FTPClientConfig}.
222 * <p> 
223 * @author Daniel F. Savarese
224 * @author Rory Winston
225 * @see FTP
226 * @see FTPConnectionClosedException
227 * @see FTPFileEntryParser
228 * @see FTPFileEntryParserFactory
229 * @see DefaultFTPFileEntryParserFactory
230 * @see FTPClientConfig
231 * 
232 * @see org.apache.commons.net.MalformedServerReplyException
233 **/
234public class FTPClient extends FTP
235implements Configurable
236{
237    /***
238     * A constant indicating the FTP session is expecting all transfers
239     * to occur between the client (local) and server and that the server
240     * should connect to the client's data port to initiate a data transfer.
241     * This is the default data connection mode when and FTPClient instance
242     * is created.
243     ***/
244    public static final int ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0;
245    /***
246     * A constant indicating the FTP session is expecting all transfers
247     * to occur between two remote servers and that the server
248     * the client is connected to should connect to the other server's
249     * data port to initiate a data transfer.
250     ***/
251    public static final int ACTIVE_REMOTE_DATA_CONNECTION_MODE = 1;
252    /***
253     * A constant indicating the FTP session is expecting all transfers
254     * to occur between the client (local) and server and that the server
255     * is in passive mode, requiring the client to connect to the
256     * server's data port to initiate a transfer.
257     ***/
258    public static final int PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2;
259    /***
260     * A constant indicating the FTP session is expecting all transfers
261     * to occur between two remote servers and that the server
262     * the client is connected to is in passive mode, requiring the other
263     * server to connect to the first server's data port to initiate a data
264     * transfer.
265     ***/
266    public static final int PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3;
267
268    private int __dataConnectionMode, __dataTimeout;
269    private int __passivePort;
270    private String __passiveHost;
271    private int __fileType, __fileFormat, __fileStructure, __fileTransferMode;
272    private boolean __remoteVerificationEnabled;
273    private long __restartOffset;
274    private FTPFileEntryParserFactory __parserFactory;
275    private int __bufferSize;
276    private boolean __listHiddenFiles;
277
278    // __systemName is a cached value that should not be referenced directly
279    // except when assigned in getSystemName and __initDefaults.
280    private String __systemName;
281
282    // __entryParser is a cached value that should not be referenced directly
283    // except when assigned in listFiles(String, String) and __initDefaults.
284    private FTPFileEntryParser __entryParser;
285    
286    private FTPClientConfig __configuration;
287
288    /** Pattern for PASV mode responses */ 
289    private static String __parms = "\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}";
290    private static java.util.regex.Pattern __parms_pat;
291    static {
292       __parms_pat = java.util.regex.Pattern.compile(__parms);
293    }
294
295    /***
296     * Default FTPClient constructor.  Creates a new FTPClient instance
297     * with the data connection mode set to
298     * <code> ACTIVE_LOCAL_DATA_CONNECTION_MODE </code>, the file type
299     * set to <code> FTP.ASCII_FILE_TYPE </code>, the
300     * file format set to <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
301     * the file structure set to <code> FTP.FILE_STRUCTURE </code>, and
302     * the transfer mode set to <code> FTP.STREAM_TRANSFER_MODE </code>.
303     ***/
304    public FTPClient()
305    {
306        __initDefaults();
307        __dataTimeout = -1;
308        __remoteVerificationEnabled = true;
309        __parserFactory = new DefaultFTPFileEntryParserFactory();
310        __configuration      = null;
311        __listHiddenFiles = false;
312    }
313
314
315    private void __initDefaults()
316    {
317        __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE;
318        __passiveHost        = null;
319        __passivePort        = -1;
320        __fileType           = FTP.ASCII_FILE_TYPE;
321        __fileStructure      = FTP.FILE_STRUCTURE;
322        __fileFormat         = FTP.NON_PRINT_TEXT_FORMAT;
323        __fileTransferMode   = FTP.STREAM_TRANSFER_MODE;
324        __restartOffset      = 0;
325        __systemName         = null;
326        __entryParser        = null;
327        __bufferSize         = Util.DEFAULT_COPY_BUFFER_SIZE;
328    }
329    
330    private String __parsePathname(String reply)
331    {
332        int begin, end;
333
334        begin = reply.indexOf('"') + 1;
335        end = reply.indexOf('"', begin);
336
337        return reply.substring(begin, end);
338    }
339
340
341    private void __parsePassiveModeReply(String reply)
342    throws MalformedServerReplyException
343    {
344        java.util.regex.Matcher m = __parms_pat.matcher(reply);
345        if (!m.find()) {
346            throw new MalformedServerReplyException(
347                "Could not parse passive host information.\nServer Reply: " + reply);
348        }
349        reply = m.group();
350        String parts[] = m.group().split(",");
351        
352        __passiveHost = parts[0] + '.' + parts[1] + '.' + parts[2] + '.' + parts[3];
353
354        try
355        {
356            int oct1 = Integer.parseInt(parts[4]);
357            int oct2 = Integer.parseInt(parts[5]);
358            __passivePort = (oct1 << 8) | oct2;
359        }
360        catch (NumberFormatException e)
361        {
362            throw new MalformedServerReplyException(
363                "Could not parse passive host information.\nServer Reply: " + reply);
364        }
365
366    }
367
368    private boolean __storeFile(int command, String remote, InputStream local)
369    throws IOException
370    {
371        OutputStream output;
372        Socket socket;
373
374        if ((socket = _openDataConnection_(command, remote)) == null)
375            return false;
376
377        output = new BufferedOutputStream(socket.getOutputStream(),
378                                          getBufferSize()
379                                          );
380        if (__fileType == ASCII_FILE_TYPE)
381            output = new ToNetASCIIOutputStream(output);
382        // Treat everything else as binary for now
383        try
384        {
385            Util.copyStream(local, output, getBufferSize(),
386                            CopyStreamEvent.UNKNOWN_STREAM_SIZE, null,
387                            false);
388        }
389        catch (IOException e)
390        {
391            try
392            {
393                socket.close();
394            }
395            catch (IOException f)
396            {}
397            throw e;
398        }
399        output.close();
400        socket.close();
401        return completePendingCommand();
402    }
403
404    private OutputStream __storeFileStream(int command, String remote)
405    throws IOException
406    {
407        OutputStream output;
408        Socket socket;
409
410        if ((socket = _openDataConnection_(command, remote)) == null)
411            return null;
412
413        output = socket.getOutputStream();
414        if (__fileType == ASCII_FILE_TYPE) {
415          // We buffer ascii transfers because the buffering has to
416          // be interposed between ToNetASCIIOutputSream and the underlying
417          // socket output stream.  We don't buffer binary transfers
418          // because we don't want to impose a buffering policy on the
419          // programmer if possible.  Programmers can decide on their
420          // own if they want to wrap the SocketOutputStream we return
421          // for file types other than ASCII.
422          output = new BufferedOutputStream(output,
423                                            getBufferSize());
424          output = new ToNetASCIIOutputStream(output);
425
426        }
427        return new org.apache.commons.net.io.SocketOutputStream(socket, output);
428    }
429
430
431    /**
432     * Establishes a data connection with the FTP server, returning
433     * a Socket for the connection if successful.  If a restart
434     * offset has been set with {@link #setRestartOffset(long)},
435     * a REST command is issued to the server with the offset as
436     * an argument before establishing the data connection.  Active
437     * mode connections also cause a local PORT command to be issued.
438     * <p>
439     * @param command  The text representation of the FTP command to send.
440     * @param arg The arguments to the FTP command.  If this parameter is
441     *             set to null, then the command is sent with no argument.
442     * @return A Socket corresponding to the established data connection.
443     *         Null is returned if an FTP protocol error is reported at
444     *         any point during the establishment and initialization of
445     *         the connection.
446     * @exception IOException  If an I/O error occurs while either sending a
447     *      command to the server or receiving a reply from the server.
448     */
449    protected Socket _openDataConnection_(int command, String arg)
450      throws IOException
451    {
452        Socket socket;
453
454        if (__dataConnectionMode != ACTIVE_LOCAL_DATA_CONNECTION_MODE &&
455                __dataConnectionMode != PASSIVE_LOCAL_DATA_CONNECTION_MODE)
456            return null;
457
458        if (__dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE)
459        {
460            ServerSocket server;
461            server = _serverSocketFactory_.createServerSocket(0, 1, getLocalAddress());
462
463            if (!FTPReply.isPositiveCompletion(port(getLocalAddress(),
464                                                    server.getLocalPort())))
465            {
466                server.close();
467                return null;
468            }
469
470            if ((__restartOffset > 0) && !restart(__restartOffset))
471            {
472                server.close();
473                return null;
474            }
475
476            if (!FTPReply.isPositivePreliminary(sendCommand(command, arg)))
477            {
478                server.close();
479                return null;
480            }
481
482            // For now, let's just use the data timeout value for waiting for
483            // the data connection.  It may be desirable to let this be a
484            // separately configurable value.  In any case, we really want
485            // to allow preventing the accept from blocking indefinitely.
486            if (__dataTimeout >= 0)
487                server.setSoTimeout(__dataTimeout);
488            try {
489                socket = server.accept();
490            } finally {
491                server.close();
492            }
493        }
494        else
495        { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE
496
497            if (pasv() != FTPReply.ENTERING_PASSIVE_MODE)
498                return null;
499
500            __parsePassiveModeReply(_replyLines.get(_replyLines.size() - 1));
501
502            socket = _socketFactory_.createSocket(__passiveHost, __passivePort);
503            if ((__restartOffset > 0) && !restart(__restartOffset))
504            {
505                socket.close();
506                return null;
507            }
508
509            if (!FTPReply.isPositivePreliminary(sendCommand(command, arg)))
510            {
511                socket.close();
512                return null;
513            }
514        }
515
516        if (__remoteVerificationEnabled && !verifyRemote(socket))
517        {
518            InetAddress host1, host2;
519
520            host1 = socket.getInetAddress();
521            host2 = getRemoteAddress();
522
523            socket.close();
524
525            throw new IOException(
526                "Host attempting data connection " + host1.getHostAddress() +
527                " is not same as server " + host2.getHostAddress());
528        }
529
530        if (__dataTimeout >= 0)
531            socket.setSoTimeout(__dataTimeout);
532
533        return socket;
534    }
535
536
537    @Override
538    protected void _connectAction_() throws IOException
539    {
540        super._connectAction_();
541        __initDefaults();
542    }
543
544
545    /***
546     * Sets the timeout in milliseconds to use when reading from the
547     * data connection.  This timeout will be set immediately after
548     * opening the data connection.
549     * <p>
550     * @param  timeout The default timeout in milliseconds that is used when
551     *        opening a data connection socket.
552     ***/
553    public void setDataTimeout(int timeout)
554    {
555        __dataTimeout = timeout;
556    }
557
558    /**
559     * set the factory used for parser creation to the supplied factory object.
560     *
561     * @param parserFactory
562     *               factory object used to create FTPFileEntryParsers
563     *
564     * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
565     * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
566     */
567    public void setParserFactory(FTPFileEntryParserFactory parserFactory) {
568        __parserFactory = parserFactory;
569    }
570
571
572    /***
573     * Closes the connection to the FTP server and restores
574     * connection parameters to the default values.
575     * <p>
576     * @exception IOException If an error occurs while disconnecting.
577     ***/
578    @Override
579    public void disconnect() throws IOException
580    {
581        super.disconnect();
582        __initDefaults();
583    }
584
585
586    /***
587     * Enable or disable verification that the remote host taking part
588     * of a data connection is the same as the host to which the control
589     * connection is attached.  The default is for verification to be
590     * enabled.  You may set this value at any time, whether the
591     * FTPClient is currently connected or not.
592     * <p>
593     * @param enable True to enable verification, false to disable verification.
594     ***/
595    public void setRemoteVerificationEnabled(boolean enable)
596    {
597        __remoteVerificationEnabled = enable;
598    }
599
600    /***
601     * Return whether or not verification of the remote host participating
602     * in data connections is enabled.  The default behavior is for
603     * verification to be enabled.
604     * <p>
605     * @return True if verification is enabled, false if not.
606     ***/
607    public boolean isRemoteVerificationEnabled()
608    {
609        return __remoteVerificationEnabled;
610    }
611
612    /***
613     * Login to the FTP server using the provided username and password.
614     * <p>
615     * @param username The username to login under.
616     * @param password The password to use.
617     * @return True if successfully completed, false if not.
618     * @exception FTPConnectionClosedException
619     *      If the FTP server prematurely closes the connection as a result
620     *      of the client being idle or some other reason causing the server
621     *      to send FTP reply code 421.  This exception may be caught either
622     *      as an IOException or independently as itself.
623     * @exception IOException  If an I/O error occurs while either sending a
624     *      command to the server or receiving a reply from the server.
625     ***/
626    public boolean login(String username, String password) throws IOException
627    {
628        user(username);
629
630        if (FTPReply.isPositiveCompletion(_replyCode))
631            return true;
632
633        // If we get here, we either have an error code, or an intermmediate
634        // reply requesting password.
635        if (!FTPReply.isPositiveIntermediate(_replyCode))
636            return false;
637
638        return FTPReply.isPositiveCompletion(pass(password));
639    }
640
641
642    /***
643     * Login to the FTP server using the provided username, password,
644     * and account.  If no account is required by the server, only
645     * the username and password, the account information is not used.
646     * <p>
647     * @param username The username to login under.
648     * @param password The password to use.
649     * @param account  The account to use.
650     * @return True if successfully completed, false if not.
651     * @exception FTPConnectionClosedException
652     *      If the FTP server prematurely closes the connection as a result
653     *      of the client being idle or some other reason causing the server
654     *      to send FTP reply code 421.  This exception may be caught either
655     *      as an IOException or independently as itself.
656     * @exception IOException  If an I/O error occurs while either sending a
657     *      command to the server or receiving a reply from the server.
658     ***/
659    public boolean login(String username, String password, String account)
660    throws IOException
661    {
662        user(username);
663
664        if (FTPReply.isPositiveCompletion(_replyCode))
665            return true;
666
667        // If we get here, we either have an error code, or an intermmediate
668        // reply requesting password.
669        if (!FTPReply.isPositiveIntermediate(_replyCode))
670            return false;
671
672        pass(password);
673
674        if (FTPReply.isPositiveCompletion(_replyCode))
675            return true;
676
677        if (!FTPReply.isPositiveIntermediate(_replyCode))
678            return false;
679
680        return FTPReply.isPositiveCompletion(acct(account));
681    }
682
683    /***
684     * Logout of the FTP server by sending the QUIT command.
685     * <p>
686     * @return True if successfully completed, false if not.
687     * @exception FTPConnectionClosedException
688     *      If the FTP server prematurely closes the connection as a result
689     *      of the client being idle or some other reason causing the server
690     *      to send FTP reply code 421.  This exception may be caught either
691     *      as an IOException or independently as itself.
692     * @exception IOException  If an I/O error occurs while either sending a
693     *      command to the server or receiving a reply from the server.
694     ***/
695    public boolean logout() throws IOException
696    {
697        return FTPReply.isPositiveCompletion(quit());
698    }
699
700
701    /***
702     * Change the current working directory of the FTP session.
703     * <p>
704     * @param pathname  The new current working directory.
705     * @return True if successfully completed, false if not.
706     * @exception FTPConnectionClosedException
707     *      If the FTP server prematurely closes the connection as a result
708     *      of the client being idle or some other reason causing the server
709     *      to send FTP reply code 421.  This exception may be caught either
710     *      as an IOException or independently as itself.
711     * @exception IOException  If an I/O error occurs while either sending a
712     *      command to the server or receiving a reply from the server.
713     ***/
714    public boolean changeWorkingDirectory(String pathname) throws IOException
715    {
716        return FTPReply.isPositiveCompletion(cwd(pathname));
717    }
718
719
720    /***
721     * Change to the parent directory of the current working directory.
722     * <p>
723     * @return True if successfully completed, false if not.
724     * @exception FTPConnectionClosedException
725     *      If the FTP server prematurely closes the connection as a result
726     *      of the client being idle or some other reason causing the server
727     *      to send FTP reply code 421.  This exception may be caught either
728     *      as an IOException or independently as itself.
729     * @exception IOException  If an I/O error occurs while either sending a
730     *      command to the server or receiving a reply from the server.
731     ***/
732    public boolean changeToParentDirectory() throws IOException
733    {
734        return FTPReply.isPositiveCompletion(cdup());
735    }
736
737
738    /***
739     * Issue the FTP SMNT command.
740     * <p>
741     * @param pathname The pathname to mount.
742     * @return True if successfully completed, false if not.
743     * @exception FTPConnectionClosedException
744     *      If the FTP server prematurely closes the connection as a result
745     *      of the client being idle or some other reason causing the server
746     *      to send FTP reply code 421.  This exception may be caught either
747     *      as an IOException or independently as itself.
748     * @exception IOException  If an I/O error occurs while either sending a
749     *      command to the server or receiving a reply from the server.
750     ***/
751    public boolean structureMount(String pathname) throws IOException
752    {
753        return FTPReply.isPositiveCompletion(smnt(pathname));
754    }
755
756    /***
757     * Reinitialize the FTP session.  Not all FTP servers support this
758     * command, which issues the FTP REIN command.
759     * <p>
760     * @return True if successfully completed, false if not.
761     * @exception FTPConnectionClosedException
762     *      If the FTP server prematurely closes the connection as a result
763     *      of the client being idle or some other reason causing the server
764     *      to send FTP reply code 421.  This exception may be caught either
765     *      as an IOException or independently as itself.
766     * @exception IOException  If an I/O error occurs while either sending a
767     *      command to the server or receiving a reply from the server.
768     ***/
769    boolean reinitialize() throws IOException
770    {
771        rein();
772
773        if (FTPReply.isPositiveCompletion(_replyCode) ||
774                (FTPReply.isPositivePreliminary(_replyCode) &&
775                 FTPReply.isPositiveCompletion(getReply())))
776        {
777
778            __initDefaults();
779
780            return true;
781        }
782
783        return false;
784    }
785
786
787    /***
788     * Set the current data connection mode to
789     * <code>ACTIVE_LOCAL_DATA_CONNECTION_MODE</code>.  No communication
790     * with the FTP server is conducted, but this causes all future data
791     * transfers to require the FTP server to connect to the client's
792     * data port.  Additionally, to accommodate differences between socket
793     * implementations on different platforms, this method causes the
794     * client to issue a PORT command before every data transfer.
795     ***/
796    public void enterLocalActiveMode()
797    {
798        __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE;
799        __passiveHost = null;
800        __passivePort = -1;
801    }
802
803
804    /***
805     * Set the current data connection mode to
806     * <code> PASSIVE_LOCAL_DATA_CONNECTION_MODE </code>.  Use this
807     * method only for data transfers between the client and server.
808     * This method causes a PASV command to be issued to the server
809     * before the opening of every data connection, telling the server to
810     * open a data port to which the client will connect to conduct
811     * data transfers.  The FTPClient will stay in
812     * <code> PASSIVE_LOCAL_DATA_CONNECTION_MODE </code> until the
813     * mode is changed by calling some other method such as
814     * {@link #enterLocalActiveMode  enterLocalActiveMode() }
815     ***/
816    public void enterLocalPassiveMode()
817    {
818        __dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE;
819        // These will be set when just before a data connection is opened
820        // in _openDataConnection_()
821        __passiveHost = null;
822        __passivePort = -1;
823    }
824
825
826    /***
827     * Set the current data connection mode to
828     * <code> ACTIVE_REMOTE_DATA_CONNECTION </code>.  Use this method only
829     * for server to server data transfers.  This method issues a PORT
830     * command to the server, indicating the other server and port to which
831     * it should connect for data transfers.  You must call this method
832     * before EVERY server to server transfer attempt.  The FTPClient will
833     * NOT automatically continue to issue PORT commands.  You also
834     * must remember to call
835     * {@link #enterLocalActiveMode  enterLocalActiveMode() } if you
836     * wish to return to the normal data connection mode.
837     * <p>
838     * @param host The passive mode server accepting connections for data
839     *             transfers.
840     * @param port The passive mode server's data port.
841     * @return True if successfully completed, false if not.
842     * @exception FTPConnectionClosedException
843     *      If the FTP server prematurely closes the connection as a result
844     *      of the client being idle or some other reason causing the server
845     *      to send FTP reply code 421.  This exception may be caught either
846     *      as an IOException or independently as itself.
847     * @exception IOException  If an I/O error occurs while either sending a
848     *      command to the server or receiving a reply from the server.
849     ***/
850    public boolean enterRemoteActiveMode(InetAddress host, int port)
851    throws IOException
852    {
853        if (FTPReply.isPositiveCompletion(port(host, port)))
854        {
855            __dataConnectionMode = ACTIVE_REMOTE_DATA_CONNECTION_MODE;
856            __passiveHost = null;
857            __passivePort = -1;
858            return true;
859        }
860        return false;
861    }
862
863    /***
864     * Set the current data connection mode to
865     * <code> PASSIVE_REMOTE_DATA_CONNECTION_MODE </code>.  Use this
866     * method only for server to server data transfers.
867     * This method issues a PASV command to the server, telling it to
868     * open a data port to which the active server will connect to conduct
869     * data transfers.  You must call this method
870     * before EVERY server to server transfer attempt.  The FTPClient will
871     * NOT automatically continue to issue PASV commands.  You also
872     * must remember to call
873     * {@link #enterLocalActiveMode  enterLocalActiveMode() } if you
874     * wish to return to the normal data connection mode.
875     * <p>
876     * @return True if successfully completed, false if not.
877     * @exception FTPConnectionClosedException
878     *      If the FTP server prematurely closes the connection as a result
879     *      of the client being idle or some other reason causing the server
880     *      to send FTP reply code 421.  This exception may be caught either
881     *      as an IOException or independently as itself.
882     * @exception IOException  If an I/O error occurs while either sending a
883     *      command to the server or receiving a reply from the server.
884     ***/
885    public boolean enterRemotePassiveMode() throws IOException
886    {
887        if (pasv() != FTPReply.ENTERING_PASSIVE_MODE)
888            return false;
889
890        __dataConnectionMode = PASSIVE_REMOTE_DATA_CONNECTION_MODE;
891        __parsePassiveModeReply(_replyLines.get(0));
892
893        return true;
894    }
895
896    /***
897     * Returns the hostname or IP address (in the form of a string) returned
898     * by the server when entering passive mode.  If not in passive mode,
899     * returns null.  This method only returns a valid value AFTER a
900     * data connection has been opened after a call to
901     * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
902     * This is because FTPClient sends a PASV command to the server only
903     * just before opening a data connection, and not when you call
904     * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
905     * <p>
906     * @return The passive host name if in passive mode, otherwise null.
907     ***/
908    public String getPassiveHost()
909    {
910        return __passiveHost;
911    }
912
913    /***
914     * If in passive mode, returns the data port of the passive host.
915     * This method only returns a valid value AFTER a
916     * data connection has been opened after a call to
917     * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
918     * This is because FTPClient sends a PASV command to the server only
919     * just before opening a data connection, and not when you call
920     * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
921     * <p>
922     * @return The data port of the passive server.  If not in passive
923     *         mode, undefined.
924     ***/
925    public int getPassivePort()
926    {
927        return __passivePort;
928    }
929
930
931    /***
932     * Returns the current data connection mode (one of the
933     * <code> _DATA_CONNECTION_MODE </code> constants.
934     * <p>
935     * @return The current data connection mode (one of the
936     * <code> _DATA_CONNECTION_MODE </code> constants.
937     ***/
938    public int getDataConnectionMode()
939    {
940        return __dataConnectionMode;
941    }
942
943
944    /***
945     * Sets the file type to be transferred.  This should be one of
946     * <code> FTP.ASCII_FILE_TYPE </code>, <code> FTP.BINARY_FILE_TYPE</code>,
947     * etc.  The file type only needs to be set when you want to change the
948     * type.  After changing it, the new type stays in effect until you change
949     * it again.  The default file type is <code> FTP.ASCII_FILE_TYPE </code>
950     * if this method is never called.
951     * <p>
952     * @param fileType The <code> _FILE_TYPE </code> constant indcating the
953     *                 type of file.
954     * @return True if successfully completed, false if not.
955     * @exception FTPConnectionClosedException
956     *      If the FTP server prematurely closes the connection as a result
957     *      of the client being idle or some other reason causing the server
958     *      to send FTP reply code 421.  This exception may be caught either
959     *      as an IOException or independently as itself.
960     * @exception IOException  If an I/O error occurs while either sending a
961     *      command to the server or receiving a reply from the server.
962     ***/
963    public boolean setFileType(int fileType) throws IOException
964    {
965        if (FTPReply.isPositiveCompletion(type(fileType)))
966        {
967            __fileType = fileType;
968            __fileFormat = FTP.NON_PRINT_TEXT_FORMAT;
969            return true;
970        }
971        return false;
972    }
973
974
975    /***
976     * Sets the file type to be transferred and the format.  The type should be
977     * one of  <code> FTP.ASCII_FILE_TYPE </code>,
978     * <code> FTP.BINARY_FILE_TYPE </code>, etc.  The file type only needs to
979     * be set when you want to change the type.  After changing it, the new
980     * type stays in effect until you change it again.  The default file type
981     * is <code> FTP.ASCII_FILE_TYPE </code> if this method is never called.
982     * The format should be one of the FTP class <code> TEXT_FORMAT </code>
983     * constants, or if the type is <code> FTP.LOCAL_FILE_TYPE </code>, the
984     * format should be the byte size for that type.  The default format
985     * is <code> FTP.NON_PRINT_TEXT_FORMAT </code> if this method is never
986     * called.
987     * <p>
988     * @param fileType The <code> _FILE_TYPE </code> constant indcating the
989     *                 type of file.
990     * @param formatOrByteSize  The format of the file (one of the
991     *              <code>_FORMAT</code> constants.  In the case of
992     *              <code>LOCAL_FILE_TYPE</code>, the byte size.
993     * <p>
994     * @return True if successfully completed, false if not.
995     * @exception FTPConnectionClosedException
996     *      If the FTP server prematurely closes the connection as a result
997     *      of the client being idle or some other reason causing the server
998     *      to send FTP reply code 421.  This exception may be caught either
999     *      as an IOException or independently as itself.
1000     * @exception IOException  If an I/O error occurs while either sending a
1001     *      command to the server or receiving a reply from the server.
1002     ***/
1003    public boolean setFileType(int fileType, int formatOrByteSize)
1004    throws IOException
1005    {
1006        if (FTPReply.isPositiveCompletion(type(fileType, formatOrByteSize)))
1007        {
1008            __fileType = fileType;
1009            __fileFormat = formatOrByteSize;
1010            return true;
1011        }
1012        return false;
1013    }
1014
1015
1016    /***
1017     * Sets the file structure.  The default structure is
1018     * <code> FTP.FILE_STRUCTURE </code> if this method is never called.
1019     * <p>
1020     * @param structure  The structure of the file (one of the FTP class
1021     *         <code>_STRUCTURE</code> constants).
1022     * @return True if successfully completed, false if not.
1023     * @exception FTPConnectionClosedException
1024     *      If the FTP server prematurely closes the connection as a result
1025     *      of the client being idle or some other reason causing the server
1026     *      to send FTP reply code 421.  This exception may be caught either
1027     *      as an IOException or independently as itself.
1028     * @exception IOException  If an I/O error occurs while either sending a
1029     *      command to the server or receiving a reply from the server.
1030     ***/
1031    public boolean setFileStructure(int structure) throws IOException
1032    {
1033        if (FTPReply.isPositiveCompletion(stru(structure)))
1034        {
1035            __fileStructure = structure;
1036            return true;
1037        }
1038        return false;
1039    }
1040
1041
1042    /***
1043     * Sets the transfer mode.  The default transfer mode
1044     * <code> FTP.STREAM_TRANSFER_MODE </code> if this method is never called.
1045     * <p>
1046     * @param mode  The new transfer mode to use (one of the FTP class
1047     *         <code>_TRANSFER_MODE</code> constants).
1048     * @return True if successfully completed, false if not.
1049     * @exception FTPConnectionClosedException
1050     *      If the FTP server prematurely closes the connection as a result
1051     *      of the client being idle or some other reason causing the server
1052     *      to send FTP reply code 421.  This exception may be caught either
1053     *      as an IOException or independently as itself.
1054     * @exception IOException  If an I/O error occurs while either sending a
1055     *      command to the server or receiving a reply from the server.
1056     ***/
1057    public boolean setFileTransferMode(int mode) throws IOException
1058    {
1059        if (FTPReply.isPositiveCompletion(mode(mode)))
1060        {
1061            __fileTransferMode = mode;
1062            return true;
1063        }
1064        return false;
1065    }
1066
1067
1068    /***
1069     * Initiate a server to server file transfer.  This method tells the
1070     * server to which the client is connected to retrieve a given file from
1071     * the other server.
1072     * <p>
1073     * @param filename  The name of the file to retrieve.
1074     * @return True if successfully completed, false if not.
1075     * @exception FTPConnectionClosedException
1076     *      If the FTP server prematurely closes the connection as a result
1077     *      of the client being idle or some other reason causing the server
1078     *      to send FTP reply code 421.  This exception may be caught either
1079     *      as an IOException or independently as itself.
1080     * @exception IOException  If an I/O error occurs while either sending a
1081     *      command to the server or receiving a reply from the server.
1082     ***/
1083    public boolean remoteRetrieve(String filename) throws IOException
1084    {
1085        if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
1086                __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE)
1087            return FTPReply.isPositivePreliminary(retr(filename));
1088        return false;
1089    }
1090
1091
1092    /***
1093     * Initiate a server to server file transfer.  This method tells the
1094     * server to which the client is connected to store a file on
1095     * the other server using the given filename.  The other server must
1096     * have had a <code> remoteRetrieve </code> issued to it by another
1097     * FTPClient.
1098     * <p>
1099     * @param filename  The name to call the file that is to be stored.
1100     * @return True if successfully completed, false if not.
1101     * @exception FTPConnectionClosedException
1102     *      If the FTP server prematurely closes the connection as a result
1103     *      of the client being idle or some other reason causing the server
1104     *      to send FTP reply code 421.  This exception may be caught either
1105     *      as an IOException or independently as itself.
1106     * @exception IOException  If an I/O error occurs while either sending a
1107     *      command to the server or receiving a reply from the server.
1108     ***/
1109    public boolean remoteStore(String filename) throws IOException
1110    {
1111        if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
1112                __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE)
1113            return FTPReply.isPositivePreliminary(stor(filename));
1114        return false;
1115    }
1116
1117
1118    /***
1119     * Initiate a server to server file transfer.  This method tells the
1120     * server to which the client is connected to store a file on
1121     * the other server using a unique filename based on the given filename.
1122     * The other server must have had a <code> remoteRetrieve </code> issued
1123     * to it by another FTPClient.
1124     * <p>
1125     * @param filename  The name on which to base the filename of the file
1126     *                  that is to be stored.
1127     * @return True if successfully completed, false if not.
1128     * @exception FTPConnectionClosedException
1129     *      If the FTP server prematurely closes the connection as a result
1130     *      of the client being idle or some other reason causing the server
1131     *      to send FTP reply code 421.  This exception may be caught either
1132     *      as an IOException or independently as itself.
1133     * @exception IOException  If an I/O error occurs while either sending a
1134     *      command to the server or receiving a reply from the server.
1135     ***/
1136    public boolean remoteStoreUnique(String filename) throws IOException
1137    {
1138        if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
1139                __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE)
1140            return FTPReply.isPositivePreliminary(stou(filename));
1141        return false;
1142    }
1143
1144
1145    /***
1146     * Initiate a server to server file transfer.  This method tells the
1147     * server to which the client is connected to store a file on
1148     * the other server using a unique filename.
1149     * The other server must have had a <code> remoteRetrieve </code> issued
1150     * to it by another FTPClient.  Many FTP servers require that a base
1151     * filename be given from which the unique filename can be derived.  For
1152     * those servers use the other version of <code> remoteStoreUnique</code>
1153     * <p>
1154     * @return True if successfully completed, false if not.
1155     * @exception FTPConnectionClosedException
1156     *      If the FTP server prematurely closes the connection as a result
1157     *      of the client being idle or some other reason causing the server
1158     *      to send FTP reply code 421.  This exception may be caught either
1159     *      as an IOException or independently as itself.
1160     * @exception IOException  If an I/O error occurs while either sending a
1161     *      command to the server or receiving a reply from the server.
1162     ***/
1163    public boolean remoteStoreUnique() throws IOException
1164    {
1165        if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
1166                __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE)
1167            return FTPReply.isPositivePreliminary(stou());
1168        return false;
1169    }
1170
1171    // For server to server transfers
1172    /***
1173     * Initiate a server to server file transfer.  This method tells the
1174     * server to which the client is connected to append to a given file on
1175     * the other server.  The other server must have had a
1176     * <code> remoteRetrieve </code> issued to it by another FTPClient.
1177     * <p>
1178     * @param filename  The name of the file to be appended to, or if the
1179     *        file does not exist, the name to call the file being stored.
1180     * <p>
1181     * @return True if successfully completed, false if not.
1182     * @exception FTPConnectionClosedException
1183     *      If the FTP server prematurely closes the connection as a result
1184     *      of the client being idle or some other reason causing the server
1185     *      to send FTP reply code 421.  This exception may be caught either
1186     *      as an IOException or independently as itself.
1187     * @exception IOException  If an I/O error occurs while either sending a
1188     *      command to the server or receiving a reply from the server.
1189     ***/
1190    public boolean remoteAppend(String filename) throws IOException
1191    {
1192        if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE ||
1193                __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE)
1194            return FTPReply.isPositivePreliminary(stor(filename));
1195        return false;
1196    }
1197
1198    /***
1199     * There are a few FTPClient methods that do not complete the
1200     * entire sequence of FTP commands to complete a transaction.  These
1201     * commands require some action by the programmer after the reception
1202     * of a positive intermediate command.  After the programmer's code
1203     * completes its actions, it must call this method to receive
1204     * the completion reply from the server and verify the success of the
1205     * entire transaction.
1206     * <p>
1207     * For example,
1208     * <pre>
1209     * InputStream input;
1210     * OutputStream output;
1211     * input  = new FileInputStream("foobaz.txt");
1212     * output = ftp.storeFileStream("foobar.txt")
1213     * if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
1214     *     input.close();
1215     *     output.close();
1216     *     ftp.logout();
1217     *     ftp.disconnect();
1218     *     System.err.println("File transfer failed.");
1219     *     System.exit(1);
1220     * }
1221     * Util.copyStream(input, output);
1222     * input.close();
1223     * output.close();
1224     * // Must call completePendingCommand() to finish command.
1225     * if(!ftp.completePendingCommand()) {
1226     *     ftp.logout();
1227     *     ftp.disconnect();
1228     *     System.err.println("File transfer failed.");
1229     *     System.exit(1);
1230     * }
1231     * </pre>
1232     * <p>
1233     * @return True if successfully completed, false if not.
1234     * @exception FTPConnectionClosedException
1235     *      If the FTP server prematurely closes the connection as a result
1236     *      of the client being idle or some other reason causing the server
1237     *      to send FTP reply code 421.  This exception may be caught either
1238     *      as an IOException or independently as itself.
1239     * @exception IOException  If an I/O error occurs while either sending a
1240     *      command to the server or receiving a reply from the server.
1241     ***/
1242    public boolean completePendingCommand() throws IOException
1243    {
1244        return FTPReply.isPositiveCompletion(getReply());
1245    }
1246
1247
1248    /***
1249     * Retrieves a named file from the server and writes it to the given
1250     * OutputStream.  This method does NOT close the given OutputStream.
1251     * If the current file type is ASCII, line separators in the file are
1252     * converted to the local representation.
1253     * <p>
1254     * @param remote  The name of the remote file.
1255     * @param local   The local OutputStream to which to write the file.
1256     * @return True if successfully completed, false if not.
1257     * @exception FTPConnectionClosedException
1258     *      If the FTP server prematurely closes the connection as a result
1259     *      of the client being idle or some other reason causing the server
1260     *      to send FTP reply code 421.  This exception may be caught either
1261     *      as an IOException or independently as itself.
1262     * @exception CopyStreamException  If an I/O error occurs while actually
1263     *      transferring the file.  The CopyStreamException allows you to
1264     *      determine the number of bytes transferred and the IOException
1265     *      causing the error.  This exception may be caught either
1266     *      as an IOException or independently as itself.
1267     * @exception IOException  If an I/O error occurs while either sending a
1268     *      command to the server or receiving a reply from the server.
1269     ***/
1270    public boolean retrieveFile(String remote, OutputStream local)
1271    throws IOException
1272    {
1273        InputStream input;
1274        Socket socket;
1275
1276        if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null)
1277            return false;
1278
1279        input = new BufferedInputStream(socket.getInputStream(),
1280                                        getBufferSize());
1281        if (__fileType == ASCII_FILE_TYPE)
1282          input = new FromNetASCIIInputStream(input);
1283        // Treat everything else as binary for now
1284        try
1285        {
1286            Util.copyStream(input, local, getBufferSize(),
1287                            CopyStreamEvent.UNKNOWN_STREAM_SIZE, null,
1288                            false);
1289        }
1290        catch (IOException e)
1291        {
1292            try
1293            {
1294                socket.close();
1295            }
1296            catch (IOException f)
1297            {}
1298            throw e;
1299        }
1300        socket.close();
1301        return completePendingCommand();
1302    }
1303
1304    /***
1305     * Returns an InputStream from which a named file from the server
1306     * can be read.  If the current file type is ASCII, the returned
1307     * InputStream will convert line separators in the file to
1308     * the local representation.  You must close the InputStream when you
1309     * finish reading from it.  The InputStream itself will take care of
1310     * closing the parent data connection socket upon being closed.  To
1311     * finalize the file transfer you must call
1312     * {@link #completePendingCommand  completePendingCommand } and
1313     * check its return value to verify success.
1314     * <p>
1315     * @param remote  The name of the remote file.
1316     * @return An InputStream from which the remote file can be read.  If
1317     *      the data connection cannot be opened (e.g., the file does not
1318     *      exist), null is returned (in which case you may check the reply
1319     *      code to determine the exact reason for failure).
1320     * @exception FTPConnectionClosedException
1321     *      If the FTP server prematurely closes the connection as a result
1322     *      of the client being idle or some other reason causing the server
1323     *      to send FTP reply code 421.  This exception may be caught either
1324     *      as an IOException or independently as itself.
1325     * @exception IOException  If an I/O error occurs while either sending a
1326     *      command to the server or receiving a reply from the server.
1327     ***/
1328    public InputStream retrieveFileStream(String remote) throws IOException
1329    {
1330        InputStream input;
1331        Socket socket;
1332
1333        if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null)
1334            return null;
1335
1336        input = socket.getInputStream();
1337        if (__fileType == ASCII_FILE_TYPE) {
1338          // We buffer ascii transfers because the buffering has to
1339          // be interposed between FromNetASCIIOutputSream and the underlying
1340          // socket input stream.  We don't buffer binary transfers
1341          // because we don't want to impose a buffering policy on the
1342          // programmer if possible.  Programmers can decide on their
1343          // own if they want to wrap the SocketInputStream we return
1344          // for file types other than ASCII.
1345          input = new BufferedInputStream(input,
1346                                          getBufferSize());
1347          input = new FromNetASCIIInputStream(input);
1348        }
1349        return new org.apache.commons.net.io.SocketInputStream(socket, input);
1350    }
1351
1352
1353    /***
1354     * Stores a file on the server using the given name and taking input
1355     * from the given InputStream.  This method does NOT close the given
1356     * InputStream.  If the current file type is ASCII, line separators in
1357     * the file are transparently converted to the NETASCII format (i.e.,
1358     * you should not attempt to create a special InputStream to do this).
1359     * <p>
1360     * @param remote  The name to give the remote file.
1361     * @param local   The local InputStream from which to read the file.
1362     * @return True if successfully completed, false if not.
1363     * @exception FTPConnectionClosedException
1364     *      If the FTP server prematurely closes the connection as a result
1365     *      of the client being idle or some other reason causing the server
1366     *      to send FTP reply code 421.  This exception may be caught either
1367     *      as an IOException or independently as itself.
1368     * @exception CopyStreamException  If an I/O error occurs while actually
1369     *      transferring the file.  The CopyStreamException allows you to
1370     *      determine the number of bytes transferred and the IOException
1371     *      causing the error.  This exception may be caught either
1372     *      as an IOException or independently as itself.
1373     * @exception IOException  If an I/O error occurs while either sending a
1374     *      command to the server or receiving a reply from the server.
1375     ***/
1376    public boolean storeFile(String remote, InputStream local)
1377    throws IOException
1378    {
1379        return __storeFile(FTPCommand.STOR, remote, local);
1380    }
1381
1382
1383    /***
1384     * Returns an OutputStream through which data can be written to store
1385     * a file on the server using the given name.  If the current file type
1386     * is ASCII, the returned OutputStream will convert line separators in
1387     * the file to the NETASCII format  (i.e., you should not attempt to
1388     * create a special OutputStream to do this).  You must close the
1389     * OutputStream when you finish writing to it.  The OutputStream itself
1390     * will take care of closing the parent data connection socket upon being
1391     * closed.  To finalize the file transfer you must call
1392     * {@link #completePendingCommand  completePendingCommand } and
1393     * check its return value to verify success.
1394     * <p>
1395     * @param remote  The name to give the remote file.
1396     * @return An OutputStream through which the remote file can be written.  If
1397     *      the data connection cannot be opened (e.g., the file does not
1398     *      exist), null is returned (in which case you may check the reply
1399     *      code to determine the exact reason for failure).
1400     * @exception FTPConnectionClosedException
1401     *      If the FTP server prematurely closes the connection as a result
1402     *      of the client being idle or some other reason causing the server
1403     *      to send FTP reply code 421.  This exception may be caught either
1404     *      as an IOException or independently as itself.
1405     * @exception IOException  If an I/O error occurs while either sending a
1406     *      command to the server or receiving a reply from the server.
1407     ***/
1408    public OutputStream storeFileStream(String remote) throws IOException
1409    {
1410        return __storeFileStream(FTPCommand.STOR, remote);
1411    }
1412
1413    /***
1414     * Appends to a file on the server with the given name, taking input
1415     * from the given InputStream.  This method does NOT close the given
1416     * InputStream.  If the current file type is ASCII, line separators in
1417     * the file are transparently converted to the NETASCII format (i.e.,
1418     * you should not attempt to create a special InputStream to do this).
1419     * <p>
1420     * @param remote  The name of the remote file.
1421     * @param local   The local InputStream from which to read the data to
1422     *                be appended to the remote file.
1423     * @return True if successfully completed, false if not.
1424     * @exception FTPConnectionClosedException
1425     *      If the FTP server prematurely closes the connection as a result
1426     *      of the client being idle or some other reason causing the server
1427     *      to send FTP reply code 421.  This exception may be caught either
1428     *      as an IOException or independently as itself.
1429     * @exception CopyStreamException  If an I/O error occurs while actually
1430     *      transferring the file.  The CopyStreamException allows you to
1431     *      determine the number of bytes transferred and the IOException
1432     *      causing the error.  This exception may be caught either
1433     *      as an IOException or independently as itself.
1434     * @exception IOException  If an I/O error occurs while either sending a
1435     *      command to the server or receiving a reply from the server.
1436     ***/
1437    public boolean appendFile(String remote, InputStream local)
1438    throws IOException
1439    {
1440        return __storeFile(FTPCommand.APPE, remote, local);
1441    }
1442
1443    /***
1444     * Returns an OutputStream through which data can be written to append
1445     * to a file on the server with the given name.  If the current file type
1446     * is ASCII, the returned OutputStream will convert line separators in
1447     * the file to the NETASCII format  (i.e., you should not attempt to
1448     * create a special OutputStream to do this).  You must close the
1449     * OutputStream when you finish writing to it.  The OutputStream itself
1450     * will take care of closing the parent data connection socket upon being
1451     * closed.  To finalize the file transfer you must call
1452     * {@link #completePendingCommand  completePendingCommand } and
1453     * check its return value to verify success.
1454     * <p>
1455     * @param remote  The name of the remote file.
1456     * @return An OutputStream through which the remote file can be appended.
1457     *      If the data connection cannot be opened (e.g., the file does not
1458     *      exist), null is returned (in which case you may check the reply
1459     *      code to determine the exact reason for failure).
1460     * @exception FTPConnectionClosedException
1461     *      If the FTP server prematurely closes the connection as a result
1462     *      of the client being idle or some other reason causing the server
1463     *      to send FTP reply code 421.  This exception may be caught either
1464     *      as an IOException or independently as itself.
1465     * @exception IOException  If an I/O error occurs while either sending a
1466     *      command to the server or receiving a reply from the server.
1467     ***/
1468    public OutputStream appendFileStream(String remote) throws IOException
1469    {
1470        return __storeFileStream(FTPCommand.APPE, remote);
1471    }
1472
1473    /***
1474     * Stores a file on the server using a unique name derived from the
1475     * given name and taking input
1476     * from the given InputStream.  This method does NOT close the given
1477     * InputStream.  If the current file type is ASCII, line separators in
1478     * the file are transparently converted to the NETASCII format (i.e.,
1479     * you should not attempt to create a special InputStream to do this).
1480     * <p>
1481     * @param remote  The name on which to base the unique name given to
1482     *                the remote file.
1483     * @param local   The local InputStream from which to read the file.
1484     * @return True if successfully completed, false if not.
1485     * @exception FTPConnectionClosedException
1486     *      If the FTP server prematurely closes the connection as a result
1487     *      of the client being idle or some other reason causing the server
1488     *      to send FTP reply code 421.  This exception may be caught either
1489     *      as an IOException or independently as itself.
1490     * @exception CopyStreamException  If an I/O error occurs while actually
1491     *      transferring the file.  The CopyStreamException allows you to
1492     *      determine the number of bytes transferred and the IOException
1493     *      causing the error.  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 storeUniqueFile(String remote, InputStream local)
1499    throws IOException
1500    {
1501        return __storeFile(FTPCommand.STOU, remote, local);
1502    }
1503
1504
1505    /***
1506     * Returns an OutputStream through which data can be written to store
1507     * a file on the server using a unique name derived from the given name.
1508     * If the current file type
1509     * is ASCII, the returned OutputStream will convert line separators in
1510     * the file to the NETASCII format  (i.e., you should not attempt to
1511     * create a special OutputStream to do this).  You must close the
1512     * OutputStream when you finish writing to it.  The OutputStream itself
1513     * will take care of closing the parent data connection socket upon being
1514     * closed.  To finalize the file transfer you must call
1515     * {@link #completePendingCommand  completePendingCommand } and
1516     * check its return value to verify success.
1517     * <p>
1518     * @param remote  The name on which to base the unique name given to
1519     *                the remote file.
1520     * @return An OutputStream through which the remote file can be written.  If
1521     *      the data connection cannot be opened (e.g., the file does not
1522     *      exist), null is returned (in which case you may check the reply
1523     *      code to determine the exact reason for failure).
1524     * @exception FTPConnectionClosedException
1525     *      If the FTP server prematurely closes the connection as a result
1526     *      of the client being idle or some other reason causing the server
1527     *      to send FTP reply code 421.  This exception may be caught either
1528     *      as an IOException or independently as itself.
1529     * @exception IOException  If an I/O error occurs while either sending a
1530     *      command to the server or receiving a reply from the server.
1531     ***/
1532    public OutputStream storeUniqueFileStream(String remote) throws IOException
1533    {
1534        return __storeFileStream(FTPCommand.STOU, remote);
1535    }
1536
1537    /**
1538     * Stores a file on the server using a unique name assigned by the
1539     * server and taking input from the given InputStream.  This method does
1540     * NOT close the given
1541     * InputStream.  If the current file type is ASCII, line separators in
1542     * the file are transparently converted to the NETASCII format (i.e.,
1543     * you should not attempt to create a special InputStream to do this).
1544     * <p>
1545     * @param local   The local InputStream from which to read the file.
1546     * @return True if successfully completed, false if not.
1547     * @exception FTPConnectionClosedException
1548     *      If the FTP server prematurely closes the connection as a result
1549     *      of the client being idle or some other reason causing the server
1550     *      to send FTP reply code 421.  This exception may be caught either
1551     *      as an IOException or independently as itself.
1552     * @exception CopyStreamException  If an I/O error occurs while actually
1553     *      transferring the file.  The CopyStreamException allows you to
1554     *      determine the number of bytes transferred and the IOException
1555     *      causing the error.  This exception may be caught either
1556     *      as an IOException or independently as itself.
1557     * @exception IOException  If an I/O error occurs while either sending a
1558     *      command to the server or receiving a reply from the server.
1559     */
1560    public boolean storeUniqueFile(InputStream local) throws IOException
1561    {
1562        return __storeFile(FTPCommand.STOU, null, local);
1563    }
1564
1565    /**
1566     * Returns an OutputStream through which data can be written to store
1567     * a file on the server using a unique name assigned by the server.
1568     * If the current file type
1569     * is ASCII, the returned OutputStream will convert line separators in
1570     * the file to the NETASCII format  (i.e., you should not attempt to
1571     * create a special OutputStream to do this).  You must close the
1572     * OutputStream when you finish writing to it.  The OutputStream itself
1573     * will take care of closing the parent data connection socket upon being
1574     * closed.  To finalize the file transfer you must call
1575     * {@link #completePendingCommand  completePendingCommand } and
1576     * check its return value to verify success.
1577     * <p>
1578     * @return An OutputStream through which the remote file can be written.  If
1579     *      the data connection cannot be opened (e.g., the file does not
1580     *      exist), null is returned (in which case you may check the reply
1581     *      code to determine the exact reason for failure).
1582     * @exception FTPConnectionClosedException
1583     *      If the FTP server prematurely closes the connection as a result
1584     *      of the client being idle or some other reason causing the server
1585     *      to send FTP reply code 421.  This exception may be caught either
1586     *      as an IOException or independently as itself.
1587     * @exception IOException  If an I/O error occurs while either sending a
1588     *      command to the server or receiving a reply from the server.
1589     */
1590    public OutputStream storeUniqueFileStream() throws IOException
1591    {
1592        return __storeFileStream(FTPCommand.STOU, null);
1593    }
1594
1595    /***
1596     * Reserve a number of bytes on the server for the next file transfer.
1597     * <p>
1598     * @param bytes  The number of bytes which the server should allocate.
1599     * @return True if successfully completed, false if not.
1600     * @exception FTPConnectionClosedException
1601     *      If the FTP server prematurely closes the connection as a result
1602     *      of the client being idle or some other reason causing the server
1603     *      to send FTP reply code 421.  This exception may be caught either
1604     *      as an IOException or independently as itself.
1605     * @exception IOException  If an I/O error occurs while either sending a
1606     *      command to the server or receiving a reply from the server.
1607     ***/
1608    public boolean allocate(int bytes) throws IOException
1609    {
1610        return FTPReply.isPositiveCompletion(allo(bytes));
1611    }
1612
1613
1614    /**
1615     * Reserve space on the server for the next file transfer.
1616     * <p>
1617     * @param bytes  The number of bytes which the server should allocate.
1618     * @param recordSize  The size of a file record.
1619     * @return True if successfully completed, false if not.
1620     * @exception FTPConnectionClosedException
1621     *      If the FTP server prematurely closes the connection as a result
1622     *      of the client being idle or some other reason causing the server
1623     *      to send FTP reply code 421.  This exception may be caught either
1624     *      as an IOException or independently as itself.
1625     * @exception IOException  If an I/O error occurs while either sending a
1626     *      command to the server or receiving a reply from the server.
1627     */
1628    public boolean allocate(int bytes, int recordSize) throws IOException
1629    {
1630        return FTPReply.isPositiveCompletion(allo(bytes, recordSize));
1631    }
1632
1633
1634    /***
1635     * Restart a <code>STREAM_TRANSFER_MODE</code> file transfer starting
1636     * from the given offset.  This will only work on FTP servers supporting
1637     * the REST comand for the stream transfer mode.  However, most FTP
1638     * servers support this.  Any subsequent file transfer will start
1639     * reading or writing the remote file from the indicated offset.
1640     * <p>
1641     * @param offset  The offset into the remote file at which to start the
1642     *           next file transfer.
1643     * @return True if successfully completed, false if not.
1644     * @exception FTPConnectionClosedException
1645     *      If the FTP server prematurely closes the connection as a result
1646     *      of the client being idle or some other reason causing the server
1647     *      to send FTP reply code 421.  This exception may be caught either
1648     *      as an IOException or independently as itself.
1649     * @exception IOException  If an I/O error occurs while either sending a
1650     *      command to the server or receiving a reply from the server.
1651     ***/
1652    private boolean restart(long offset) throws IOException
1653    {
1654        __restartOffset = 0;
1655        return FTPReply.isPositiveIntermediate(rest(Long.toString(offset)));
1656    }
1657
1658    /***
1659     * Sets the restart offset.  The restart command is sent to the server
1660     * only before sending the file transfer command.  When this is done,
1661     * the restart marker is reset to zero.
1662     * <p>
1663     * @param offset  The offset into the remote file at which to start the
1664     *           next file transfer.  This must be a value greater than or
1665     *           equal to zero.
1666     ***/
1667    public void setRestartOffset(long offset)
1668    {
1669        if (offset >= 0)
1670            __restartOffset = offset;
1671    }
1672
1673    /***
1674     * Fetches the restart offset.
1675     * <p>
1676     * @return offset  The offset into the remote file at which to start the
1677     *           next file transfer.
1678     ***/
1679    public long getRestartOffset()
1680    {
1681        return __restartOffset;
1682    }
1683
1684
1685
1686    /***
1687     * Renames a remote file.
1688     * <p>
1689     * @param from  The name of the remote file to rename.
1690     * @param to    The new name of the remote file.
1691     * @return True if successfully completed, false if not.
1692     * @exception FTPConnectionClosedException
1693     *      If the FTP server prematurely closes the connection as a result
1694     *      of the client being idle or some other reason causing the server
1695     *      to send FTP reply code 421.  This exception may be caught either
1696     *      as an IOException or independently as itself.
1697     * @exception IOException  If an I/O error occurs while either sending a
1698     *      command to the server or receiving a reply from the server.
1699     ***/
1700    public boolean rename(String from, String to) throws IOException
1701    {
1702        if (!FTPReply.isPositiveIntermediate(rnfr(from)))
1703            return false;
1704
1705        return FTPReply.isPositiveCompletion(rnto(to));
1706    }
1707
1708
1709    /***
1710     * Abort a transfer in progress.
1711     * <p>
1712     * @return True if successfully completed, false if not.
1713     * @exception FTPConnectionClosedException
1714     *      If the FTP server prematurely closes the connection as a result
1715     *      of the client being idle or some other reason causing the server
1716     *      to send FTP reply code 421.  This exception may be caught either
1717     *      as an IOException or independently as itself.
1718     * @exception IOException  If an I/O error occurs while either sending a
1719     *      command to the server or receiving a reply from the server.
1720     ***/
1721    public boolean abort() throws IOException
1722    {
1723        return FTPReply.isPositiveCompletion(abor());
1724    }
1725
1726    /***
1727     * Deletes a file on the FTP server.
1728     * <p>
1729     * @param pathname   The pathname of the file to be deleted.
1730     * @return True if successfully completed, false if not.
1731     * @exception FTPConnectionClosedException
1732     *      If the FTP server prematurely closes the connection as a result
1733     *      of the client being idle or some other reason causing the server
1734     *      to send FTP reply code 421.  This exception may be caught either
1735     *      as an IOException or independently as itself.
1736     * @exception IOException  If an I/O error occurs while either sending a
1737     *      command to the server or receiving a reply from the server.
1738     ***/
1739    public boolean deleteFile(String pathname) throws IOException
1740    {
1741        return FTPReply.isPositiveCompletion(dele(pathname));
1742    }
1743
1744
1745    /***
1746     * Removes a directory on the FTP server (if empty).
1747     * <p>
1748     * @param pathname  The pathname of the directory to remove.
1749     * @return True if successfully completed, false if not.
1750     * @exception FTPConnectionClosedException
1751     *      If the FTP server prematurely closes the connection as a result
1752     *      of the client being idle or some other reason causing the server
1753     *      to send FTP reply code 421.  This exception may be caught either
1754     *      as an IOException or independently as itself.
1755     * @exception IOException  If an I/O error occurs while either sending a
1756     *      command to the server or receiving a reply from the server.
1757     ***/
1758    public boolean removeDirectory(String pathname) throws IOException
1759    {
1760        return FTPReply.isPositiveCompletion(rmd(pathname));
1761    }
1762
1763
1764    /***
1765     * Creates a new subdirectory on the FTP server in the current directory
1766     * (if a relative pathname is given) or where specified (if an absolute
1767     * pathname is given).
1768     * <p>
1769     * @param pathname The pathname of the directory to create.
1770     * @return True if successfully completed, false if not.
1771     * @exception FTPConnectionClosedException
1772     *      If the FTP server prematurely closes the connection as a result
1773     *      of the client being idle or some other reason causing the server
1774     *      to send FTP reply code 421.  This exception may be caught either
1775     *      as an IOException or independently as itself.
1776     * @exception IOException  If an I/O error occurs while either sending a
1777     *      command to the server or receiving a reply from the server.
1778     ***/
1779    public boolean makeDirectory(String pathname) throws IOException
1780    {
1781        return FTPReply.isPositiveCompletion(mkd(pathname));
1782    }
1783
1784
1785    /***
1786     * Returns the pathname of the current working directory.
1787     * <p>
1788     * @return The pathname of the current working directory.  If it cannot
1789     *         be obtained, returns null.
1790     * @exception FTPConnectionClosedException
1791     *      If the FTP server prematurely closes the connection as a result
1792     *      of the client being idle or some other reason causing the server
1793     *      to send FTP reply code 421.  This exception may be caught either
1794     *      as an IOException or independently as itself.
1795     * @exception IOException  If an I/O error occurs while either sending a
1796     *      command to the server or receiving a reply from the server.
1797     ***/
1798    public String printWorkingDirectory() throws IOException
1799    {
1800        if (pwd() != FTPReply.PATHNAME_CREATED)
1801            return null;
1802
1803        return __parsePathname(_replyLines.get( _replyLines.size() - 1));
1804    }
1805
1806
1807    /**
1808     * Send a site specific command.
1809     * @param arguments The site specific command and arguments.
1810     * @return True if successfully completed, false if not.
1811     * @exception FTPConnectionClosedException
1812     *      If the FTP server prematurely closes the connection as a result
1813     *      of the client being idle or some other reason causing the server
1814     *      to send FTP reply code 421.  This exception may be caught either
1815     *      as an IOException or independently as itself.
1816     * @exception IOException  If an I/O error occurs while either sending a
1817     *      command to the server or receiving a reply from the server.
1818     */
1819    public boolean sendSiteCommand(String arguments) throws IOException
1820    {
1821        return FTPReply.isPositiveCompletion(site(arguments));
1822    }
1823
1824
1825    /***
1826     * Fetches the system type name from the server and returns the string.
1827     * This value is cached for the duration of the connection after the
1828     * first call to this method.  In other words, only the first time
1829     * that you invoke this method will it issue a SYST command to the
1830     * FTP server.  FTPClient will remember the value and return the
1831     * cached value until a call to disconnect.
1832     * <p>
1833     * @return The system type name obtained from the server.  null if the
1834     *       information could not be obtained.
1835     * @exception FTPConnectionClosedException
1836     *      If the FTP server prematurely closes the connection as a result
1837     *      of the client being idle or some other reason causing the server
1838     *      to send FTP reply code 421.  This exception may be caught either
1839     *      as an IOException or independently as itself.
1840     * @exception IOException  If an I/O error occurs while either sending a
1841     *  command to the server or receiving a reply from the server.
1842     ***/
1843    public String getSystemName() throws IOException
1844    {
1845      //if (syst() == FTPReply.NAME_SYSTEM_TYPE)
1846      // Technically, we should expect a NAME_SYSTEM_TYPE response, but
1847      // in practice FTP servers deviate, so we soften the condition to
1848      // a positive completion.
1849        if (__systemName == null && FTPReply.isPositiveCompletion(syst()))
1850            __systemName = _replyLines.get(_replyLines.size() - 1).substring(4);
1851
1852        return __systemName;
1853    }
1854
1855
1856    /***
1857     * Fetches the system help information from the server and returns the
1858     * full string.
1859     * <p>
1860     * @return The system help string obtained from the server.  null if the
1861     *       information could not be obtained.
1862     * @exception FTPConnectionClosedException
1863     *      If the FTP server prematurely closes the connection as a result
1864     *      of the client being idle or some other reason causing the server
1865     *      to send FTP reply code 421.  This exception may be caught either
1866     *      as an IOException or independently as itself.
1867     * @exception IOException  If an I/O error occurs while either sending a
1868     *  command to the server or receiving a reply from the server.
1869     ***/
1870    public String listHelp() throws IOException
1871    {
1872        if (FTPReply.isPositiveCompletion(help()))
1873            return getReplyString();
1874        return null;
1875    }
1876
1877
1878    /**
1879     * Fetches the help information for a given command from the server and
1880     * returns the full string.
1881     * @param command The command on which to ask for help.
1882     * @return The command help string obtained from the server.  null if the
1883     *       information could not be obtained.
1884     * @exception FTPConnectionClosedException
1885     *      If the FTP server prematurely closes the connection as a result
1886     *      of the client being idle or some other reason causing the server
1887     *      to send FTP reply code 421.  This exception may be caught either
1888     *      as an IOException or independently as itself.
1889     * @exception IOException  If an I/O error occurs while either sending a
1890     *  command to the server or receiving a reply from the server.
1891     */
1892    public String listHelp(String command) throws IOException
1893    {
1894        if (FTPReply.isPositiveCompletion(help(command)))
1895            return getReplyString();
1896        return null;
1897    }
1898
1899
1900    /***
1901     * Sends a NOOP command to the FTP server.  This is useful for preventing
1902     * server timeouts.
1903     * <p>
1904     * @return True if successfully completed, false if not.
1905     * @exception FTPConnectionClosedException
1906     *      If the FTP server prematurely closes the connection as a result
1907     *      of the client being idle or some other reason causing the server
1908     *      to send FTP reply code 421.  This exception may be caught either
1909     *      as an IOException or independently as itself.
1910     * @exception IOException  If an I/O error occurs while either sending a
1911     *      command to the server or receiving a reply from the server.
1912     ***/
1913    public boolean sendNoOp() throws IOException
1914    {
1915        return FTPReply.isPositiveCompletion(noop());
1916    }
1917    
1918
1919    /***
1920     * Obtain a list of filenames in a directory (or just the name of a given
1921     * file, which is not particularly useful).  This information is obtained
1922     * through the NLST command.  If the given pathname is a directory and
1923     * contains no files,  a zero length array is returned only
1924     * if the FTP server returned a positive completion code, otherwise
1925     * null is returned (the FTP server returned a 550 error No files found.).
1926     * If the directory is not empty, an array of filenames in the directory is
1927     * returned. If the pathname corresponds
1928     * to a file, only that file will be listed.  The server may or may not
1929     * expand glob expressions.
1930     * <p>
1931     * @param pathname  The file or directory to list.
1932     * @return The list of filenames contained in the given path.  null if
1933     *     the list could not be obtained.  If there are no filenames in
1934     *     the directory, a zero-length array is returned.
1935     * @exception FTPConnectionClosedException
1936     *      If the FTP server prematurely closes the connection as a result
1937     *      of the client being idle or some other reason causing the server
1938     *      to send FTP reply code 421.  This exception may be caught either
1939     *      as an IOException or independently as itself.
1940     * @exception IOException  If an I/O error occurs while either sending a
1941     *      command to the server or receiving a reply from the server.
1942     ***/
1943    public String[] listNames(String pathname) throws IOException
1944    {
1945        String line;
1946        Socket socket;
1947        BufferedReader reader;
1948        ArrayList<String> results;
1949
1950        if ((socket = _openDataConnection_(FTPCommand.NLST, pathname)) == null)
1951            return null;
1952
1953        reader =
1954            new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding()));
1955
1956        results = new ArrayList<String>();
1957        while ((line = reader.readLine()) != null)
1958            results.add(line);
1959        
1960        reader.close();
1961        socket.close();
1962
1963        if (completePendingCommand())
1964        {
1965            String[] names = new String[ results.size() ];
1966            return results.toArray(names);
1967        }
1968
1969        return null;
1970    }
1971
1972
1973    /***
1974     * Obtain a list of filenames in the current working directory
1975     * This information is obtained through the NLST command.  If the current
1976     * directory contains no files, a zero length array is returned only
1977     * if the FTP server returned a positive completion code, otherwise,
1978     * null is returned (the FTP server returned a 550 error No files found.).
1979     * If the directory is not empty, an array of filenames in the directory is
1980     * returned.
1981     * <p>
1982     * @return The list of filenames contained in the current working
1983     *     directory.  null if the list could not be obtained.
1984     *     If there are no filenames in the directory, a zero-length array
1985     *     is returned.
1986     * @exception FTPConnectionClosedException
1987     *      If the FTP server prematurely closes the connection as a result
1988     *      of the client being idle or some other reason causing the server
1989     *      to send FTP reply code 421.  This exception may be caught either
1990     *      as an IOException or independently as itself.
1991     * @exception IOException  If an I/O error occurs while either sending a
1992     *      command to the server or receiving a reply from the server.
1993     ***/
1994    public String[] listNames() throws IOException
1995    {
1996        return listNames(null);
1997    }
1998
1999
2000
2001    /**
2002     * Using the default system autodetect mechanism, obtain a
2003     * list of file information for the current working directory
2004     * or for just a single file.
2005     * <p>
2006     * This information is obtained through the LIST command.  The contents of
2007     * the returned array is determined by the<code> FTPFileEntryParser </code>
2008     * used.
2009     * <p>
2010     * @param pathname  The file or directory to list.  Since the server may
2011     *                  or may not expand glob expressions, using them here
2012     *                  is not recommended and may well cause this method to
2013     *                  fail.
2014     *
2015     * @return The list of file information contained in the given path in
2016     *         the format determined by the autodetection mechanism
2017     * @exception FTPConnectionClosedException
2018     *                   If the FTP server prematurely closes the connection
2019     *                   as a result of the client being idle or some other
2020     *                   reason causing the server to send FTP reply code 421.
2021     *                   This exception may be caught either as an IOException
2022     *                   or independently as itself.
2023     * @exception IOException
2024     *                   If an I/O error occurs while either sending a
2025     *                   command to the server or receiving a reply
2026     *                   from the server.
2027     * @exception ParserInitializationException
2028     *                   Thrown if the parserKey parameter cannot be
2029     *                   resolved by the selected parser factory.
2030     *                   In the DefaultFTPEntryParserFactory, this will
2031     *                   happen when parserKey is neither
2032     *                   the fully qualified class name of a class
2033     *                   implementing the interface
2034     *                   org.apache.commons.net.ftp.FTPFileEntryParser
2035     *                   nor a string containing one of the recognized keys
2036     *                   mapping to such a parser or if class loader
2037     *                   security issues prevent its being loaded.
2038     * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
2039     * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
2040     * @see org.apache.commons.net.ftp.FTPFileEntryParser
2041     */
2042    public FTPFile[] listFiles(String pathname)
2043    throws IOException
2044    {
2045        String key = null;
2046        FTPListParseEngine engine =
2047            initiateListParsing(key, pathname);
2048        return engine.getFiles();
2049
2050    }
2051    /**
2052     * Using the default system autodetect mechanism, obtain a
2053     * list of file information for the current working directory.
2054     * <p>
2055     * This information is obtained through the LIST command.  The contents of
2056     * the returned array is determined by the<code> FTPFileEntryParser </code>
2057     * used.
2058     * <p>
2059     * @return The list of file information contained in the current directory
2060     *         in the format determined by the autodetection mechanism.  
2061     *         <p><b> 
2062     *         NOTE:</b> This array may contain null members if any of the 
2063     *         individual file listings failed to parse.  The caller should 
2064     *         check each entry for null before referencing it.
2065     * @exception FTPConnectionClosedException
2066     *                   If the FTP server prematurely closes the connection
2067     *                   as a result of the client being idle or some other
2068     *                   reason causing the server to send FTP reply code 421.
2069     *                   This exception may be caught either as an IOException
2070     *                   or independently as itself.
2071     * @exception IOException
2072     *                   If an I/O error occurs while either sending a
2073     *                   command to the server or receiving a reply
2074     *                   from the server.
2075     * @exception ParserInitializationException
2076     *                   Thrown if the parserKey parameter cannot be
2077     *                   resolved by the selected parser factory.
2078     *                   In the DefaultFTPEntryParserFactory, this will
2079     *                   happen when parserKey is neither
2080     *                   the fully qualified class name of a class
2081     *                   implementing the interface
2082     *                   org.apache.commons.net.ftp.FTPFileEntryParser
2083     *                   nor a string containing one of the recognized keys
2084     *                   mapping to such a parser or if class loader
2085     *                   security issues prevent its being loaded.
2086     * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
2087     * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
2088     * @see org.apache.commons.net.ftp.FTPFileEntryParser
2089     */
2090    public FTPFile[] listFiles()
2091    throws IOException
2092    {
2093        return listFiles((String) null);
2094    }
2095
2096    /**
2097     * Using the default autodetect mechanism, initialize an FTPListParseEngine
2098     * object containing a raw file information for the current working
2099     * directory on the server
2100     * This information is obtained through the LIST command.  This object
2101     * is then capable of being iterated to return a sequence of FTPFile
2102     * objects with information filled in by the
2103     * <code> FTPFileEntryParser </code> used.
2104     * <p>
2105     * This method differs from using the listFiles() methods in that
2106     * expensive FTPFile objects are not created until needed which may be
2107     * an advantage on large lists.
2108     *
2109     * @return A FTPListParseEngine object that holds the raw information and
2110     * is capable of providing parsed FTPFile objects, one for each file
2111     * containing information contained in the given path in the format
2112     * determined by the <code> parser </code> parameter.   Null will be
2113     * returned if a data connection cannot be opened.  If the current working
2114     * directory contains no files, an empty array will be the return.
2115     *
2116     * @exception FTPConnectionClosedException
2117     *                   If the FTP server prematurely closes the connection as a result
2118     *                   of the client being idle or some other reason causing the server
2119     *                   to send FTP reply code 421.  This exception may be caught either
2120     *                   as an IOException or independently as itself.
2121     * @exception IOException
2122     *                   If an I/O error occurs while either sending a
2123     *                   command to the server or receiving a reply from the server.
2124     * @exception ParserInitializationException
2125     *                   Thrown if the autodetect mechanism cannot
2126     *                   resolve the type of system we are connected with.
2127     * @see FTPListParseEngine
2128     */
2129    public FTPListParseEngine initiateListParsing()
2130    throws IOException
2131    {
2132        return initiateListParsing((String) null);
2133    }
2134
2135    /**
2136     * Using the default autodetect mechanism, initialize an FTPListParseEngine
2137     * object containing a raw file information for the supplied directory.
2138     * This information is obtained through the LIST command.  This object
2139     * is then capable of being iterated to return a sequence of FTPFile
2140     * objects with information filled in by the
2141     * <code> FTPFileEntryParser </code> used.
2142     * <p>
2143     * The server may or may not expand glob expressions.  You should avoid
2144     * using glob expressions because the return format for glob listings
2145     * differs from server to server and will likely cause this method to fail.
2146     * <p>
2147     * This method differs from using the listFiles() methods in that
2148     * expensive FTPFile objects are not created until needed which may be
2149     * an advantage on large lists.
2150     * <p>
2151     * <pre>
2152     *    FTPClient f=FTPClient();
2153     *    f.connect(server);
2154     *    f.login(username, password);
2155     *    FTPListParseEngine engine = f.initiateListParsing(directory);
2156     *
2157     *    while (engine.hasNext()) {
2158     *       FTPFile[] files = engine.getNext(25);  // "page size" you want
2159     *       //do whatever you want with these files, display them, etc.
2160     *       //expensive FTPFile objects not created until needed.
2161     *    }
2162     * </pre>
2163     *
2164     * @return A FTPListParseEngine object that holds the raw information and
2165     * is capable of providing parsed FTPFile objects, one for each file
2166     * containing information contained in the given path in the format
2167     * determined by the <code> parser </code> parameter.   Null will be
2168     * returned if a data connection cannot be opened.  If the current working
2169     * directory contains no files, an empty array will be the return.
2170     *
2171     * @exception FTPConnectionClosedException
2172     *                   If the FTP server prematurely closes the connection as a result
2173     *                   of the client being idle or some other reason causing the server
2174     *                   to send FTP reply code 421.  This exception may be caught either
2175     *                   as an IOException or independently as itself.
2176     * @exception IOException
2177     *                   If an I/O error occurs while either sending a
2178     *                   command to the server or receiving a reply from the server.
2179     * @exception ParserInitializationException
2180     *                   Thrown if the autodetect mechanism cannot
2181     *                   resolve the type of system we are connected with.
2182     * @see FTPListParseEngine
2183     */
2184    public FTPListParseEngine initiateListParsing(
2185            String pathname)
2186    throws IOException
2187    {
2188        String key = null;
2189        return initiateListParsing(key, pathname);
2190    }
2191
2192    /**
2193     * Using the supplied parser key, initialize an FTPListParseEngine
2194     * object containing a raw file information for the supplied directory.
2195     * This information is obtained through the LIST command.  This object
2196     * is then capable of being iterated to return a sequence of FTPFile
2197     * objects with information filled in by the
2198     * <code> FTPFileEntryParser </code> used.
2199     * <p>
2200     * The server may or may not expand glob expressions.  You should avoid
2201     * using glob expressions because the return format for glob listings
2202     * differs from server to server and will likely cause this method to fail.
2203     * <p>
2204     * This method differs from using the listFiles() methods in that
2205     * expensive FTPFile objects are not created until needed which may be
2206     * an advantage on large lists.
2207     *
2208     * @param parserKey A string representing a designated code or fully-qualified
2209     * class name of an  <code> FTPFileEntryParser </code> that should be
2210     *               used to parse each server file listing.
2211     *
2212     * @return A FTPListParseEngine object that holds the raw information and
2213     * is capable of providing parsed FTPFile objects, one for each file
2214     * containing information contained in the given path in the format
2215     * determined by the <code> parser </code> parameter.   Null will be
2216     * returned if a data connection cannot be opened.  If the current working
2217     * directory contains no files, an empty array will be the return.
2218     *
2219     * @exception FTPConnectionClosedException
2220     *                   If the FTP server prematurely closes the connection as a result
2221     *                   of the client being idle or some other reason causing the server
2222     *                   to send FTP reply code 421.  This exception may be caught either
2223     *                   as an IOException or independently as itself.
2224     * @exception IOException
2225     *                   If an I/O error occurs while either sending a
2226     *                   command to the server or receiving a reply from the server.
2227     * @exception ParserInitializationException
2228     *                   Thrown if the parserKey parameter cannot be
2229     *                   resolved by the selected parser factory.
2230     *                   In the DefaultFTPEntryParserFactory, this will
2231     *                   happen when parserKey is neither
2232     *                   the fully qualified class name of a class
2233     *                   implementing the interface
2234     *                   org.apache.commons.net.ftp.FTPFileEntryParser
2235     *                   nor a string containing one of the recognized keys
2236     *                   mapping to such a parser or if class loader
2237     *                   security issues prevent its being loaded.
2238     * @see FTPListParseEngine
2239     */
2240    public FTPListParseEngine initiateListParsing(
2241            String parserKey, String pathname)
2242    throws IOException
2243    {
2244        // We cache the value to avoid creation of a new object every
2245        // time a file listing is generated.
2246        if(__entryParser == null) {
2247            if (null != parserKey) {
2248                // if a parser key was supplied in the parameters, 
2249                // use that to create the paraser
2250                __entryParser = 
2251                    __parserFactory.createFileEntryParser(parserKey);
2252                
2253            } else {
2254                // if no parserKey was supplied, check for a configuration
2255                // in the params, and if non-null, use that.
2256                if (null != __configuration) {
2257                    __entryParser = 
2258                        __parserFactory.createFileEntryParser(__configuration);
2259                } else {
2260                    // if a parserKey hasn't been supplied, and a configuration
2261                    // hasn't been supplied, then autodetect by calling
2262                    // the SYST command and use that to choose the parser.
2263                    __entryParser = 
2264                        __parserFactory.createFileEntryParser(getSystemName());
2265                }
2266            }
2267        }
2268
2269        return initiateListParsing(__entryParser, pathname);
2270
2271    }
2272
2273
2274    /**
2275     * private method through which all listFiles() and
2276     * initiateListParsing methods pass once a parser is determined.
2277     *
2278     * @exception FTPConnectionClosedException
2279     *                   If the FTP server prematurely closes the connection as a result
2280     *                   of the client being idle or some other reason causing the server
2281     *                   to send FTP reply code 421.  This exception may be caught either
2282     *                   as an IOException or independently as itself.
2283     * @exception IOException
2284     *                   If an I/O error occurs while either sending a
2285     *                   command to the server or receiving a reply from the server.
2286     * @see FTPListParseEngine
2287     */
2288    private FTPListParseEngine initiateListParsing(
2289            FTPFileEntryParser parser, String pathname)
2290    throws IOException
2291    {
2292        Socket socket;
2293
2294        FTPListParseEngine engine = new FTPListParseEngine(parser);
2295
2296        if ((socket = _openDataConnection_(FTPCommand.LIST, getListArguments(pathname))) == null)
2297        {
2298            return engine;
2299        }
2300
2301
2302        try {
2303            engine.readServerList(socket.getInputStream(), getControlEncoding());
2304        }
2305        finally {
2306            socket.close();
2307        }
2308
2309        completePendingCommand();
2310        return engine;
2311    }
2312
2313    /**
2314     * @since 2.0
2315     */
2316    protected String getListArguments(String pathname) {
2317        if (getListHiddenFiles())
2318        {
2319            StringBuffer sb = new StringBuffer(pathname.length() + 3);
2320            sb.append("-a ");
2321            sb.append(pathname);
2322            return sb.toString();
2323        }
2324        
2325        return pathname;
2326    }
2327
2328
2329    /***
2330     * Issue the FTP STAT command to the server.
2331     * <p>
2332     * @return The status information returned by the server.
2333     * @exception FTPConnectionClosedException
2334     *      If the FTP server prematurely closes the connection as a result
2335     *      of the client being idle or some other reason causing the server
2336     *      to send FTP reply code 421.  This exception may be caught either
2337     *      as an IOException or independently as itself.
2338     * @exception IOException  If an I/O error occurs while either sending a
2339     *      command to the server or receiving a reply from the server.
2340     ***/
2341    public String getStatus() throws IOException
2342    {
2343        if (FTPReply.isPositiveCompletion(stat()))
2344            return getReplyString();
2345        return null;
2346    }
2347
2348
2349    /***
2350     * Issue the FTP STAT command to the server for a given pathname.  This
2351     * should produce a listing of the file or directory.
2352     * <p>
2353     * @return The status information returned by the server.
2354     * @exception FTPConnectionClosedException
2355     *      If the FTP server prematurely closes the connection as a result
2356     *      of the client being idle or some other reason causing the server
2357     *      to send FTP reply code 421.  This exception may be caught either
2358     *      as an IOException or independently as itself.
2359     * @exception IOException  If an I/O error occurs while either sending a
2360     *      command to the server or receiving a reply from the server.
2361     ***/
2362    public String getStatus(String pathname) throws IOException
2363    {
2364        if (FTPReply.isPositiveCompletion(stat(pathname)))
2365            return getReplyString();
2366        return null;
2367    }
2368    
2369    
2370    /**
2371     * Issue the FTP MDTM command (not supported by all servers to retrieve the last
2372     * modification time of a file. The modification string should be in the 
2373     * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in 
2374     * GMT, but not all FTP servers honour this.
2375     * 
2376     * @param pathname The file path to query.
2377     * @return A string representing the last file modification time in <code>YYYYMMDDhhmmss</code> format.
2378     * @throws IOException if an I/O error occurs.
2379     * @since 2.0
2380     */
2381    public String getModificationTime(String pathname) throws IOException {
2382        if (FTPReply.isPositiveCompletion(mdtm(pathname)))
2383            return getReplyString();
2384        return null;
2385    }
2386
2387
2388    /**
2389     * Set the internal buffer size.
2390     *  
2391     * @param bufSize The size of the buffer
2392     */
2393    public void setBufferSize(int bufSize) {
2394        __bufferSize = bufSize;
2395    }
2396    
2397    /**
2398     * Retrieve the current internal buffer size.
2399     * @return The current buffer size.
2400     */
2401    public int getBufferSize() {
2402        return __bufferSize;
2403    }
2404
2405
2406    /** 
2407     * Implementation of the {@link Configurable Configurable} interface. 
2408     * In the case of this class, configuring merely makes the config object available for the
2409     * factory methods that construct parsers.
2410     * @param config {@link FTPClientConfig FTPClientConfig} object used to 
2411     * provide non-standard configurations to the parser.
2412     * @since 1.4
2413     */
2414    public void configure(FTPClientConfig config) {
2415        this.__configuration = config;
2416    }
2417
2418    /**
2419     * You can set this to true if you would like to get hidden files when {@link #listFiles} too.
2420     * A <code>LIST -a</code> will be issued to the ftp server.
2421     * It depends on your ftp server if you need to call this method, also dont expect to get rid
2422     * of hidden files if you call this method with "false".
2423     * 
2424     * @param listHiddenFiles true if hidden files should be listed 
2425     * @since 2.0
2426     */
2427    public void setListHiddenFiles(boolean listHiddenFiles) {
2428        this.__listHiddenFiles = listHiddenFiles;
2429    }
2430
2431    /**
2432     * @see #setListHiddenFiles(boolean)
2433     * @return the current state
2434     * @since 2.0
2435     */
2436    public boolean getListHiddenFiles() {
2437        return this.__listHiddenFiles;
2438    }
2439}
2440
2441/* Emacs configuration
2442 * Local variables:        **
2443 * mode:             java  **
2444 * c-basic-offset:   4     **
2445 * indent-tabs-mode: nil   **
2446 * End:                    **
2447 */