Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/enterprisedt/net/ftp/FTPClient.java


1   /**
2    *
3    *  Java FTP client library.
4    *
5    *  Copyright (C) 2000  Enterprise Distributed Technologies Ltd
6    *
7    *  www.enterprisedt.com
8    *
9    *  This library is free software; you can redistribute it and/or
10   *  modify it under the terms of the GNU Lesser General Public
11   *  License as published by the Free Software Foundation; either
12   *  version 2.1 of the License, or (at your option) any later version.
13   *
14   *  This library is distributed in the hope that it will be useful,
15   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   *  Lesser General Public License for more details.
18   *
19   *  You should have received a copy of the GNU Lesser General Public
20   *  License along with this library; if not, write to the Free Software
21   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22   *
23   *  Bug fixes, suggestions and comments should be sent to:
24   *
25   *  bruceb@cryptsoft.com
26   *
27   *  or by snail mail to:
28   *
29   *  Bruce P. Blackshaw
30   *  53 Wakehurst Road
31   *  London SW11 6DB
32   *  United Kingdom
33   *
34   *  Change Log:
35   *
36   *
37   *        2002/07/04 7:32:46 PM  Michael Kandelaars
38   *        Added get method that returns an
39   *        InputStream
40   *
41   *        $Log: FTPClient.java,v $
42   *        Revision 1.3  2001/10/09 20:53:46  bruceb
43   *        Active mode changes
44   *
45   *        Revision 1.1  2001/10/05 14:42:03  bruceb
46   *        moved from old project
47   *
48   *
49   */
50  
51  
52  package com.enterprisedt.net.ftp;
53  
54  import java.io.IOException;
55  import java.io.LineNumberReader;
56  import java.io.InputStreamReader;
57  import java.io.OutputStreamWriter;
58  import java.io.BufferedWriter;
59  import java.io.FileWriter;
60  import java.io.FileReader;
61  import java.io.InputStream;
62  import java.io.DataInputStream;
63  import java.io.DataOutputStream;
64  import java.io.BufferedInputStream;
65  import java.io.BufferedOutputStream;
66  import java.io.FileOutputStream;
67  import java.io.FileInputStream;
68  import java.io.File;
69  
70  import java.net.InetAddress;
71  import java.net.Socket;
72  
73  import java.util.Vector;
74  import java.util.Properties;
75  
76  /**
77   *  Supports client-side FTP. Most common
78   *  FTP operations are present in this class.
79   *
80   *  @author             Bruce Blackshaw
81   *  @version        $Revision: 1.3 $
82   *
83   */
84  public class FTPClient {
85  
86      /**
87       *  Revision control id
88       */
89      private static String cvsId = "$Id: FTPClient.java,v 1.3 2001/10/09 20:53:46 bruceb Exp $";
90  
91      /**
92       *  Socket responsible for controlling
93       *  the connection
94       */
95      private FTPControlSocket control = null;
96  
97      /**
98       *  Socket responsible for transferring
99       *  the data
100      */
101     private FTPDataSocket data = null;
102 
103 
104     /**
105      *  Socket timeout for both data and control. In
106      *  milliseconds
107      */
108     private int timeout = 0;
109 
110 
111     /**
112      *  Record of the transfer type - make the default ASCII
113      */
114     private FTPTransferType transferType = FTPTransferType.ASCII;
115 
116     /**
117      *  Record of the connect mode - make the default PASV (as this was
118      *  the original mode supported)
119      */
120     private FTPConnectMode connectMode = FTPConnectMode.PASV;
121 
122     /**
123      *  Constructor. Creates the control
124      *  socket
125      *
126      *  @param   remoteHost  the remote hostname
127      */
128     public FTPClient(String remoteHost)
129         throws IOException, FTPException {
130 
131         control = new FTPControlSocket(remoteHost);
132     }
133 
134     /**
135      *  Constructor. Creates the control
136      *  socket
137      *
138      *  @param   remoteHost  the remote hostname
139      *  @param   controlPort  port for control stream
140      */
141     public FTPClient(String remoteHost, int controlPort)
142         throws IOException, FTPException {
143 
144         control = new FTPControlSocket(remoteHost, controlPort);
145     }
146 
147     /**
148      *  Constructor. Creates the control
149      *  socket
150      *
151      *  @param   remoteAddr  the address of the
152      *                       remote host
153      */
154     public FTPClient(InetAddress remoteAddr)
155         throws IOException, FTPException {
156 
157         control = new FTPControlSocket(remoteAddr);
158     }
159 
160 
161     /**
162      *  Constructor. Creates the control
163      *  socket. Allows setting of control port (normally
164      *  set by default to 21).
165      *
166      *  @param   remoteAddr  the address of the
167      *                       remote host
168      *  @param   controlPort  port for control stream
169      */
170     public FTPClient(InetAddress remoteAddr, int controlPort)
171         throws IOException, FTPException {
172 
173         control = new FTPControlSocket(remoteAddr, controlPort);
174     }
175 
176 
177     /**
178      *   Set the TCP timeout on the underlying socket.
179      *
180      *   If a timeout is set, then any operation which
181      *   takes longer than the timeout value will be
182      *   killed with a java.io.InterruptedException. We
183      *   set both the control and data connections
184      *
185      *   @param millis The length of the timeout, in milliseconds
186      */
187     public void setTimeout(int millis)
188         throws IOException {
189 
190         this.timeout = millis;
191         control.setTimeout(millis);
192     }
193 
194 
195     /**
196      *  Set the connect mode
197      *
198      *  @param  mode  ACTIVE or PASV mode
199      */
200     public void setConnectMode(FTPConnectMode mode) {
201 
202         connectMode = mode;
203     }
204 
205 
206     /**
207      *  Login into an account on the FTP server. This
208      *  call completes the entire login process
209      *
210      *  @param   user       user name
211      *  @param   password   user's password
212      */
213     public void login(String user, String password)
214         throws IOException, FTPException {
215 
216         String response = control.sendCommand("USER " + user);
217         control.validateReply(response, "331");
218         response = control.sendCommand("PASS " + password);
219         control.validateReply(response, "230");
220     }
221 
222 
223     /**
224      *  Supply the user name to log into an account
225      *  on the FTP server. Must be followed by the
226      *  password() method - but we allow for
227      *
228      *  @param   user       user name
229      *  @param   password   user's password
230      */
231     public void user(String user)
232         throws IOException, FTPException {
233 
234         String reply = control.sendCommand("USER " + user);
235 
236         // we allow for a site with no password - 230 response
237         String[] validCodes = {"230", "331"};
238         control.validateReply(reply, validCodes);
239     }
240 
241 
242     /**
243      *  Supplies the password for a previously supplied
244      *  username to log into the FTP server. Must be
245      *  preceeded by the user() method
246      *
247      *  @param   user       user name
248      *  @param   password   user's password
249      */
250     public void password(String password)
251         throws IOException, FTPException {
252 
253         String reply = control.sendCommand("PASS " + password);
254 
255         // we allow for a site with no passwords (202)
256         String[] validCodes = {"230", "202"};
257         control.validateReply(reply, validCodes);
258     }
259 
260     /**
261      *  Set up SOCKS v4 proxy settings. This can be used if there
262      *  is a SOCKS proxy server in place that must be connected thru.
263      *
264      *  @param  port  SOCKS proxy port
265      *  @param  host  SOCKS proxy hostname
266      */
267     public void initSOCKS(String port, String host) {
268 
269         Properties props = System.getProperties();
270         props.put("socksProxyPort", port);
271         props.put("socksProxyHost", host);
272         System.setProperties(props);
273     }
274 
275 
276     /**
277      *  Get the name of the remote host
278      *
279      *  @return  remote host name
280      */
281     String getRemoteHostName() {
282         return control.getRemoteHostName();
283     }
284 
285 
286     /**
287      *  Issue arbitrary ftp commands to the FTP server.
288      *
289      *  @param command     ftp command to be sent to server
290      *  @param validCodes  valid return codes for this command
291      */
292     public void quote(String command, String[] validCodes)
293         throws IOException, FTPException {
294 
295         String reply = control.sendCommand(command);
296 
297         // allow for no validation to be supplied
298         if (validCodes != null && validCodes.length > 0)
299             control.validateReply(reply, validCodes);
300     }
301 
302 
303     /**
304      *  Put a local file onto the FTP server. It
305      *  is placed in the current directory.
306      *
307      *  @param  localPath   path of the local file
308      *  @param  remoteFile  name of remote file in
309      *                      current directory
310      */
311     public void put(String localPath, String remoteFile)
312         throws IOException, FTPException {
313 
314         put(localPath, remoteFile, false);
315     }
316 
317 
318     /**
319      *  Put a local file onto the FTP server. It
320      *  is placed in the current directory. Allows appending
321      *  if current file exists
322      *
323      *  @param  localPath   path of the local file
324      *  @param  remoteFile  name of remote file in
325      *                      current directory
326      *  @param  append      true if appending, false otherwise
327      */
328     public void put(String localPath, String remoteFile, boolean append)
329         throws IOException, FTPException {
330 
331         // get according to set type
332         if (getType() == FTPTransferType.ASCII) {
333             putASCII(localPath, remoteFile, append);
334         }
335         else {
336             putBinary(localPath, remoteFile, append);
337         }
338 
339         // check the control response
340         String[] validCodes2 = {"226", "250"};
341         String reply = control.readReply();
342         control.validateReply(reply, validCodes2);
343     }
344 
345 
346     /**
347      *  Request the server to set up the put
348      *
349      *  @param  remoteFile  name of remote file in
350      *                      current directory
351      *  @param  append      true if appending, false otherwise
352      */
353     private void initPut(String remoteFile, boolean append)
354         throws IOException, FTPException {
355 
356         // set up data channel
357         data = control.createDataSocket(connectMode);
358         data.setTimeout(timeout);
359 
360         // send the command to store
361         String cmd = append ? "APPE " : "STOR ";
362         String reply = control.sendCommand(cmd + remoteFile);
363 
364         // Can get a 125 or a 150
365         String[] validCodes1 = {"125", "150"};
366         control.validateReply(reply, validCodes1);
367     }
368 
369 
370     /**
371      *  Put as ASCII, i.e. read a line at a time and write
372      *  inserting the correct FTP separator
373      *
374      *  @param localPath   full path of local file to read from
375      *  @param remoteFile  name of remote file we are writing to
376      *  @param  append      true if appending, false otherwise
377      */
378     private void putASCII(String localPath, String remoteFile, boolean append)
379         throws IOException, FTPException {
380 
381         // create the buffered stream for reading
382         LineNumberReader in
383             = new LineNumberReader(
384                 new FileReader(localPath));
385 
386         initPut(remoteFile, append);
387 
388         // get an character output stream to write to ... AFTER we
389         // have the ok to go ahead AND AFTER we've successfully opened a
390         // stream for the local file
391         BufferedWriter out =
392             new BufferedWriter(
393                 new OutputStreamWriter(data.getOutputStream()));
394 
395         // write line by line, writing \r\n as required by RFC959 after
396         // each line
397         String line = null;
398         while ((line = in.readLine()) != null) {
399             out.write(line, 0, line.length());
400             out.write(FTPControlSocket.EOL, 0, FTPControlSocket.EOL.length());
401         }
402         in.close();
403         out.flush();
404         out.close();
405 
406         // and close the data socket
407         try {
408             data.close();
409         }
410         catch (IOException ignore) {}
411     }
412 
413 
414     /**
415      *  Put as binary, i.e. read and write raw bytes
416      *
417      *  @param localPath   full path of local file to read from
418      *  @param remoteFile  name of remote file we are writing to
419      *  @param  append      true if appending, false otherwise
420      */
421     private void putBinary(String localPath, String remoteFile, boolean append)
422         throws IOException, FTPException {
423 
424         // open input stream to read source file ... do this
425         // BEFORE opening output stream to server, so if file not
426         // found, an exception is thrown
427         BufferedInputStream in =
428             new BufferedInputStream(
429                 new FileInputStream(localPath));
430 
431         initPut(remoteFile, append);
432 
433         // get an output stream
434         BufferedOutputStream out =
435             new BufferedOutputStream(
436                 new DataOutputStream(data.getOutputStream()));
437 
438         byte[] buf = new byte[512];
439 
440         // read a chunk at a time and write to the data socket
441         int count = 0;
442         while ((count = in.read(buf)) > 0) {
443             out.write(buf, 0, count);
444         }
445         in.close();
446 
447         // flush and clean up
448         out.flush();
449         out.close();
450 
451         // and close the data socket
452         try {
453             data.close();
454         }
455         catch (IOException ignore) {}
456     }
457 
458 
459     /**
460      *  Put data onto the FTP server. It
461      *  is placed in the current directory.
462      *
463      *  @param  data        array of bytes
464      *  @param  remoteFile  name of remote file in
465      *                      current directory
466      */
467     public void put(byte[] bytes, String remoteFile)
468         throws IOException, FTPException {
469 
470         put(bytes, remoteFile, false);
471     }
472 
473     /**
474      *  Put data onto the FTP server. It
475      *  is placed in the current directory. Allows
476      *  appending if current file exists
477      *
478      *  @param  data        array of bytes
479      *  @param  remoteFile  name of remote file in
480      *                      current directory
481      *  @param  append      true if appending, false otherwise
482      */
483     public void put(byte[] bytes, String remoteFile, boolean append)
484         throws IOException, FTPException {
485 
486         initPut(remoteFile, append);
487 
488         // get an output stream
489         BufferedOutputStream out =
490             new BufferedOutputStream(
491                 new DataOutputStream(data.getOutputStream()));
492 
493         // write array
494         out.write(bytes, 0, bytes.length);
495 
496         // flush and clean up
497         out.flush();
498         out.close();
499 
500         // and close the data socket
501         try {
502             data.close();
503         }
504         catch (IOException ignore) {}
505 
506         // check the control response
507         String[] validCodes2 = {"226", "250"};
508         String reply = control.readReply();
509         control.validateReply(reply, validCodes2);
510     }
511 
512 
513     /**
514      *  Get data from the FTP server. Uses the currently
515      *  set transfer mode.
516      *
517      *  @param  localPath   local file to put data in
518      *  @param  remoteFile  name of remote file in
519      *                      current directory
520      */
521     public void get(String localPath, String remoteFile)
522         throws IOException, FTPException {
523 
524         // get according to set type
525         if (getType() == FTPTransferType.ASCII) {
526             getASCII(localPath, remoteFile);
527         }
528         else {
529             getBinary(localPath, remoteFile);
530         }
531 
532         // check the control response
533         String[] validCodes2 = {"226", "250"};
534         String reply = control.readReply();
535         control.validateReply(reply, validCodes2);
536     }
537 
538 
539     /**
540      *  Request to the server that the get is set up
541      *
542      *  @param  remoteFile  name of remote file
543      */
544     private void initGet(String remoteFile)
545         throws IOException, FTPException {
546 
547         // set up data channel
548         data = control.createDataSocket(connectMode);
549         data.setTimeout(timeout);
550 
551         // send the retrieve command
552         String reply = control.sendCommand("RETR " + remoteFile);
553 
554         // Can get a 125 or a 150
555         String[] validCodes1 = {"125", "150"};
556         control.validateReply(reply, validCodes1);
557     }
558 
559 
560     /**
561      *  Get as ASCII, i.e. read a line at a time and write
562      *  using the correct newline separator for the OS
563      *
564      *  @param localPath   full path of local file to write to
565      *  @param remoteFile  name of remote file
566      */
567     private void getASCII(String localPath, String remoteFile)
568         throws IOException, FTPException {
569 
570         // create the buffered stream for writing
571         BufferedWriter out =
572             new BufferedWriter(
573                 new FileWriter(localPath));
574 
575         initGet(remoteFile);
576 
577         // get an character input stream to read data from ... AFTER we
578         // have the ok to go ahead AND AFTER we've successfully opened a
579         // stream for the local file
580         LineNumberReader in =
581             new LineNumberReader(
582                 new InputStreamReader(data.getInputStream()));
583 
584         // read/write a line at a time
585         String line = null;
586         while ((line = in.readLine()) != null) {
587             out.write(line, 0, line.length());
588             out.newLine();
589         }
590         out.close();
591 
592         try {
593             in.close();
594             data.close();
595         }
596         catch (IOException ignore) {}
597     }
598 
599 
600     /**
601      *  Get as binary file, i.e. straight transfer of data
602      *
603      *  @param localPath   full path of local file to write to
604      *  @param remoteFile  name of remote file
605      */
606     private void getBinary(String localPath, String remoteFile)
607         throws IOException, FTPException {
608 
609         // create the buffered output stream for writing the file
610         BufferedOutputStream out =
611             new BufferedOutputStream(
612                 new FileOutputStream(localPath, false));
613 
614         initGet(remoteFile);
615 
616         // get an input stream to read data from ... AFTER we have
617         // the ok to go ahead AND AFTER we've successfully opened a
618         // stream for the local file
619         BufferedInputStream in =
620             new BufferedInputStream(
621                 new DataInputStream(data.getInputStream()));
622 
623         // do the retrieving
624         int chunksize = 4096;
625         byte [] chunk = new byte[chunksize];
626         int count;
627 
628         // read from socket & write to file in chunks
629         while ((count = in.read(chunk, 0, chunksize)) >= 0) {
630 
631             out.write(chunk, 0, count);
632         }
633         out.close();
634 
635         // close streams
636         try {
637             in.close();
638             data.close();
639         }
640         catch (IOException ignore) {}
641     }
642 
643 
644     /**
645      *  Get data from the FTP server. Transfers in
646      *  whatever mode we are in. Returns the 
647      *  InputStream for the FTP connection.
648      *
649      *  @param  remoteFile  name of remote file in
650      *                      current directory
651      *  @return InputStream  handle to the FTP
652      *                       connection
653      *  @author  Michael Kandelaars
654      *  @date  Thursday, 4 July 2002 7:32:46 PM
655      */
656     public InputStream get(String remoteFile, long byteSkip) 
657                             throws IOException, FTPException {
658        
659         String reply = "";
660 
661         // set up data channel
662         data = control.createDataSocket(connectMode);
663         data.setTimeout(timeout);
664 
665         if(byteSkip > 0) {
666             // send the rest command
667             reply = control.sendCommand("REST " + byteSkip);
668 
669             // Can get a 350
670             String validCodes1 = "350";
671             control.validateReply(reply, validCodes1);
672         }
673 
674         // send the retrieve command
675         reply = control.sendCommand("RETR " + remoteFile);
676 
677         // Can get a 125 or a 150
678         String[] validCodes2 = {"125", "150"};
679         control.validateReply(reply, validCodes2);
680 
681         return data.getInputStream();
682     }
683 
684 
685     public int getFileSize(String remoteFile) 
686                        throws IOException, FTPException {
687 
688         String reply = "";
689 
690         reply = control.sendCommand("SIZE " + remoteFile);
691 
692         // Can get a 213
693         String validCodes = "213";
694         control.validateReply(reply, validCodes);
695 
696         return Integer.parseInt(reply.substring(4));
697     }
698 
699 
700     /**
701      *  Get data from the FTP server. Transfers in
702      *  whatever mode we are in. Retrieve as a byte array. Note
703      *  that we may experience memory limitations as the
704      *  entire file must be held in memory at one time.
705      *
706      *  @param  remoteFile  name of remote file in
707      *                      current directory
708      */
709     public byte[] get(String remoteFile)
710         throws IOException, FTPException {
711 
712         // set up data channel
713         data = control.createDataSocket(connectMode);
714         data.setTimeout(timeout);
715 
716         // send the retrieve command
717         String reply = control.sendCommand("RETR " + remoteFile);
718 
719         // Can get a 125 or a 150
720         String[] validCodes1 = {"125", "150"};
721         control.validateReply(reply, validCodes1);
722 
723         // get an input stream to read data from
724         BufferedInputStream in =
725             new BufferedInputStream(
726                 new DataInputStream(data.getInputStream()));
727 
728         // do the retrieving
729         int chunksize = 4096;
730         byte [] chunk = new byte[chunksize];  // read chunks into
731         byte [] resultBuf = new byte[chunksize];  // where we place chunks
732         byte [] temp = null;  // temp swap buffer
733         int count;  // size of chunk read
734         int bufsize = 0;  // size of resultBuf
735 
736         // read from socket & write to file
737         while ((count = in.read(chunk, 0, chunksize)) >= 0) {
738 
739             // new buffer to hold current buf + new chunk
740             temp = new byte[bufsize+count];
741 
742             // copy current buf to temp
743             System.arraycopy(resultBuf, 0, temp, 0, bufsize);
744 
745             // copy new chunk onto end of temp
746             System.arraycopy(chunk, 0, temp, bufsize, count);
747 
748             // re-assign temp buffer to buf
749             resultBuf = temp;
750 
751             // update size of buffer
752             bufsize += count;
753         }
754 
755         // close streams
756         try {
757             in.close();
758             data.close();
759         }
760         catch (IOException ignore) {}
761 
762         // check the control response
763         String[] validCodes2 = {"226", "250"};
764         reply = control.readReply();
765         control.validateReply(reply, validCodes2);
766 
767         return resultBuf;
768     }
769 
770 
771     /**
772      *  Run a site-specific command on the
773      *  server. Support for commands is dependent
774      *  on the server
775      *
776      *  @param  command   the site command to run
777      *  @return true if command ok, false if
778      *          command not implemented
779      */
780     public boolean site(String command)
781         throws IOException, FTPException {
782 
783         // send the retrieve command
784         String reply = control.sendCommand("SITE " + command);
785 
786         // Can get a 200 (ok) or 202 (not impl). Some
787         // FTP servers return 502 (not impl)
788         String[] validCodes = {"200", "202", "502"};
789         control.validateReply(reply, validCodes);
790 
791         // return true or false? 200 is ok, 202/502 not
792         // implemented
793         if (reply.substring(0, 3).equals("200"))
794             return true;
795         else
796             return false;
797     }
798 
799 
800     /**
801      *  List a directory's contents
802      *
803      *  @param  mask  the file mask to use
804      *  @return a string containing the line separated
805      *          directory listing
806      *  @deprecated  As of FTP 1.1, replaced by {@link #dir(String)}
807      */
808     public String list(String mask)
809         throws IOException, FTPException {
810 
811         return list(mask, false);
812     }
813 
814 
815     /**
816      *  List a directory's contents as one string. A detailed
817      *  listing is available, otherwise just filenames are provided.
818      *  The detailed listing varies in details depending on OS and
819      *  FTP server.
820      *
821      *  @param  mask  the file mask to use
822      *  @param  full  true if detailed listing required
823      *                false otherwise
824      *  @return a string containing the line separated
825      *          directory listing
826      *  @deprecated  As of FTP 1.1, replaced by {@link #dir(String,boolean)}
827      */
828     public String list(String mask, boolean full)
829         throws IOException, FTPException {
830 
831         String[] list = dir(mask, full);
832 
833         StringBuffer result = new StringBuffer();
834         String sep = System.getProperty("line.separator");
835 
836         // loop thru results and make into one string
837         for (int i = 0; i < list.length; i++) {
838             result.append(list[i]);
839             result.append(sep);
840         }
841 
842         return result.toString();
843     }
844 
845 
846     /**
847      *  List a directory's contents as an array of strings of filenames.
848      *
849      *  @param  mask  the file mask to use
850      *  @return  an array of directory listing strings
851      */
852     public String[] dir(String mask)
853         throws IOException, FTPException {
854 
855         return dir(mask, false);
856     }
857 
858 
859     /**
860      *  List a directory's contents as an array of strings. A detailed
861      *  listing is available, otherwise just filenames are provided.
862      *  The detailed listing varies in details depending on OS and
863      *  FTP server.
864      *
865      *  @param  mask  the file mask to use
866      *  @param  full  true if detailed listing required
867      *                false otherwise
868      *  @return  an array of directory listing strings
869      */
870     public String[] dir(String mask, boolean full)
871         throws IOException, FTPException {
872 
873         // set up data channel
874         data = control.createDataSocket(connectMode);
875         data.setTimeout(timeout);
876 
877         // send the retrieve command
878         String command = full ? "LIST ":"NLST ";
879         command += mask;
880 
881         // some FTP servers bomb out if NLST has whitespace appended
882         command = command.trim();
883         String reply = control.sendCommand(command);
884 
885         // Can get a 125 or a 150
886         String[] validCodes1 = {"125", "150"};
887         control.validateReply(reply, validCodes1);
888 
889         // get an character input stream to read data from ... AFTER we
890         // have the ok to go ahead
891         LineNumberReader in =
892             new LineNumberReader(
893                 new InputStreamReader(data.getInputStream()));
894 
895         // read a line at a time
896         Vector lines = new Vector();
897         String line = null;
898         while ((line = in.readLine()) != null) {
899             lines.add(line);
900         }
901 
902         try {
903             in.close();
904             data.close();
905         }
906         catch (IOException ignore) {}
907 
908         // check the control response
909         String[] validCodes2 = {"226", "250"};
910         reply = control.readReply();
911         control.validateReply(reply, validCodes2);
912 
913         return (String[])lines.toArray(new String[0]);
914     }
915 
916 
917 
918     /**
919      *  Switch debug of responses on or off
920      *
921      *  @param  on  true if you wish to have responses to
922      *              stdout, false otherwise
923      */
924     public void debugResponses(boolean on) {
925 
926         control.debugResponses(on);
927     }
928 
929 
930     /**
931      *  Get the current transfer type
932      *
933      *  @return  the current type of the transfer,
934      *           i.e. BINARY or ASCII
935      */
936     public FTPTransferType getType() {
937 
938         return transferType;
939     }
940 
941 
942     /**
943      *  Set the transfer type
944      *
945      *  @param  type  the transfer type to
946      *                set the server to
947      */
948     public void setType(FTPTransferType type)
949         throws IOException, FTPException {
950 
951         // determine the character to send
952         String typeStr = FTPTransferType.ASCII_CHAR;
953         if (type.equals(FTPTransferType.BINARY))
954             typeStr = FTPTransferType.BINARY_CHAR;
955 
956         // send the command
957         String reply = control.sendCommand("TYPE " + typeStr);
958         control.validateReply(reply, "200");
959 
960         // record the type
961         transferType = type;
962     }
963 
964 
965     /**
966      *  Delete the specified remote file
967      *
968      *  @param  remoteFile  name of remote file to
969      *                      delete
970      */
971     public void delete(String remoteFile)
972         throws IOException, FTPException {
973 
974         String reply = control.sendCommand("DELE " + remoteFile);
975         control.validateReply(reply, "250");
976     }
977 
978 
979     /**
980      *  Rename a file or directory
981      *
982      * @param from  name of file or directory to rename
983      * @param to    intended name
984      */
985     public void rename(String from, String to)
986         throws IOException, FTPException {
987 
988         String reply = control.sendCommand("RNFR " + from);
989         control.validateReply(reply, "350");
990 
991         reply = control.sendCommand("RNTO " + to);
992         control.validateReply(reply, "250");
993     }
994 
995 
996     /**
997      *  Delete the specified remote working directory
998      *
999      *  @param  dir  name of remote directory to
1000     *               delete
1001     */
1002    public void rmdir(String dir)
1003        throws IOException, FTPException {
1004
1005        String reply = control.sendCommand("RMD " + dir);
1006        control.validateReply(reply, "250");
1007    }
1008
1009
1010    /**
1011     *  Create the specified remote working directory
1012     *
1013     *  @param  dir  name of remote directory to
1014     *               create
1015     */
1016    public void mkdir(String dir)
1017        throws IOException, FTPException {
1018
1019        String reply = control.sendCommand("MKD " + dir);
1020        control.validateReply(reply, "257");
1021    }
1022
1023
1024    /**
1025     *  Change the remote working directory to
1026     *  that supplied
1027     *
1028     *  @param  dir  name of remote directory to
1029     *               change to
1030     */
1031    public void chdir(String dir)
1032        throws IOException, FTPException {
1033
1034        String reply = control.sendCommand("CWD " + dir);
1035        control.validateReply(reply, "250");
1036    }
1037
1038
1039    /**
1040     *  Get the current remote working directory
1041     *
1042     *  @return   the current working directory
1043     */
1044    public String pwd()
1045        throws IOException, FTPException {
1046
1047        String reply = control.sendCommand("PWD");
1048        control.validateReply(reply, "257");
1049        return reply.substring(4);
1050    }
1051
1052
1053    /**
1054     *  Get the type of the OS at the server
1055     *
1056     *  @return   the type of server OS
1057     */
1058    public String system()
1059        throws IOException, FTPException {
1060
1061        String reply = control.sendCommand("SYST");
1062        control.validateReply(reply, "215");
1063        return reply.substring(4);
1064    }
1065
1066
1067    /**
1068     *  Quit the FTP session
1069     *
1070     */
1071    public void quit()
1072        throws IOException, FTPException {
1073
1074        String reply = control.sendCommand("QUIT" + FTPControlSocket.EOL);
1075        control.validateReply(reply, "221");
1076
1077        control.logout();
1078        control = null;
1079    }
1080
1081}
1082
1083
1084