KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > enterprisedt > net > ftp > FTPClient


1 /**
2  *
3  * Java FTP client library.
4  *
5  * Copyright (C) 2000-2003 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 bruce@enterprisedt.com
24  *
25  * Change Log:
26  *
27  * $Log: FTPClient.java,v $
28  * Revision 1.1.1.1 2005/06/23 15:23:01 smontoro
29  * hipergate backend
30  *
31  * Revision 1.1 2004/02/07 03:15:20 hipergate
32  * v2.0 pre-alpha
33  *
34  * Revision 1.6 2003/05/31 14:53:44 bruceb
35  * 1.2.2 changes
36  *
37  * Revision 1.5 2003/01/29 22:46:08 bruceb
38  * minor changes
39  *
40  * Revision 1.4 2002/11/19 22:01:25 bruceb
41  * changes for 1.2
42  *
43  * Revision 1.3 2001/10/09 20:53:46 bruceb
44  * Active mode changes
45  *
46  * Revision 1.1 2001/10/05 14:42:03 bruceb
47  * moved from old project
48  *
49  */

50
51 package com.enterprisedt.net.ftp;
52
53 import java.io.IOException JavaDoc;
54 import java.io.LineNumberReader JavaDoc;
55 import java.io.InputStream JavaDoc;
56 import java.io.InputStreamReader JavaDoc;
57 import java.io.OutputStream JavaDoc;
58 import java.io.OutputStreamWriter JavaDoc;
59 import java.io.PrintWriter JavaDoc;
60 import java.io.BufferedWriter JavaDoc;
61 import java.io.FileWriter JavaDoc;
62 import java.io.DataInputStream JavaDoc;
63 import java.io.DataOutputStream JavaDoc;
64 import java.io.BufferedInputStream JavaDoc;
65 import java.io.BufferedOutputStream JavaDoc;
66 import java.io.ByteArrayOutputStream JavaDoc;
67 import java.io.FileOutputStream JavaDoc;
68 import java.io.FileInputStream JavaDoc;
69 import java.io.File JavaDoc;
70
71 import java.text.SimpleDateFormat JavaDoc;
72 import java.text.ParsePosition JavaDoc;
73
74 import java.net.InetAddress JavaDoc;
75 import java.util.Date JavaDoc;
76 import java.util.Vector JavaDoc;
77 import java.util.Properties JavaDoc;
78
79 /**
80  * Supports client-side FTP. Most common
81  * FTP operations are present in this class.
82  *
83  * @author Bruce Blackshaw
84  * @version $Revision: 1.1.1.1 $
85  *
86  */

87 public class FTPClient {
88
89     /**
90      * Revision control id
91      */

92     private static String JavaDoc cvsId = "@(#)$Id: FTPClient.java,v 1.1.1.1 2005/06/23 15:23:01 smontoro Exp $";
93
94     /**
95      * Format to interpret MTDM timestamp
96      */

97     private SimpleDateFormat JavaDoc tsFormat =
98         new SimpleDateFormat JavaDoc("yyyyMMddHHmmss");
99
100     /**
101      * Socket responsible for controlling
102      * the connection
103      */

104     private FTPControlSocket control = null;
105
106     /**
107      * Socket responsible for transferring
108      * the data
109      */

110     private FTPDataSocket data = null;
111
112     /**
113      * Socket timeout for both data and control. In
114      * milliseconds
115      */

116     private int timeout = 0;
117
118     /**
119      * Record of the transfer type - make the default ASCII
120      */

121     private FTPTransferType transferType = FTPTransferType.ASCII;
122
123     /**
124      * Record of the connect mode - make the default PASV (as this was
125      * the original mode supported)
126      */

127     private FTPConnectMode connectMode = FTPConnectMode.PASV;
128
129     /**
130      * Holds the last valid reply from the server on the control socket
131      */

132     private FTPReply lastValidReply;
133
134     /**
135      * Constructor. Creates the control
136      * socket
137      *
138      * @param remoteHost the remote hostname
139      */

140     public FTPClient(String JavaDoc remoteHost)
141         throws IOException JavaDoc, FTPException {
142
143         control = new FTPControlSocket(remoteHost,
144                                        FTPControlSocket.CONTROL_PORT,
145                                        null, 0);
146     }
147
148     /**
149      * Constructor. Creates the control
150      * socket
151      *
152      * @param remoteHost the remote hostname
153      * @param controlPort port for control stream
154      */

155     public FTPClient(String JavaDoc remoteHost, int controlPort)
156         throws IOException JavaDoc, FTPException {
157
158         control = new FTPControlSocket(remoteHost, controlPort, null, 0);
159     }
160
161     /**
162      * Constructor. Creates the control
163      * socket
164      *
165      * @param remoteAddr the address of the
166      * remote host
167      */

168     public FTPClient(InetAddress JavaDoc remoteAddr)
169         throws IOException JavaDoc, FTPException {
170
171         control = new FTPControlSocket(remoteAddr,
172                                        FTPControlSocket.CONTROL_PORT,
173                                        null, 0);
174     }
175
176     /**
177      * Constructor. Creates the control
178      * socket. Allows setting of control port (normally
179      * set by default to 21).
180      *
181      * @param remoteAddr the address of the
182      * remote host
183      * @param controlPort port for control stream
184      */

185     public FTPClient(InetAddress JavaDoc remoteAddr, int controlPort)
186         throws IOException JavaDoc, FTPException {
187
188         control = new FTPControlSocket(remoteAddr, controlPort,
189                                        null, 0);
190     }
191
192     /**
193      * Constructor. Creates the control
194      * socket
195      *
196      * @param remoteHost the remote hostname
197      * @param millis the length of the timeout, in milliseconds
198      */

199     public FTPClient(String JavaDoc remoteHost, PrintWriter JavaDoc log, int timeout)
200         throws IOException JavaDoc, FTPException {
201
202         control = new FTPControlSocket(remoteHost,
203                                        FTPControlSocket.CONTROL_PORT,
204                                        log, timeout);
205     }
206
207     /**
208      * Constructor. Creates the control
209      * socket
210      *
211      * @param remoteHost the remote hostname
212      * @param controlPort port for control stream
213      * @param millis the length of the timeout, in milliseconds
214      */

215     public FTPClient(String JavaDoc remoteHost, int controlPort,
216                      PrintWriter JavaDoc log, int timeout)
217         throws IOException JavaDoc, FTPException {
218
219         control = new FTPControlSocket(remoteHost, controlPort,
220                                        log, timeout);
221     }
222
223     /**
224      * Constructor. Creates the control
225      * socket
226      *
227      * @param remoteAddr the address of the
228      * remote host
229      * @param millis the length of the timeout, in milliseconds
230      */

231     public FTPClient(InetAddress JavaDoc remoteAddr, PrintWriter JavaDoc log,
232                      int timeout)
233         throws IOException JavaDoc, FTPException {
234
235         control = new FTPControlSocket(remoteAddr,
236                                        FTPControlSocket.CONTROL_PORT,
237                                        log, timeout);
238     }
239
240     /**
241      * Constructor. Creates the control
242      * socket. Allows setting of control port (normally
243      * set by default to 21).
244      *
245      * @param remoteAddr the address of the
246      * remote host
247      * @param controlPort port for control stream
248      * @param millis the length of the timeout, in milliseconds
249      */

250     public FTPClient(InetAddress JavaDoc remoteAddr, int controlPort,
251                      PrintWriter JavaDoc log, int timeout)
252         throws IOException JavaDoc, FTPException {
253
254         control = new FTPControlSocket(remoteAddr, controlPort,
255                                        log, timeout);
256     }
257
258     /**
259      * Set the TCP timeout on the underlying socket.
260      *
261      * If a timeout is set, then any operation which
262      * takes longer than the timeout value will be
263      * killed with a java.io.InterruptedException. We
264      * set both the control and data connections
265      *
266      * @param millis The length of the timeout, in milliseconds
267      */

268     public void setTimeout(int millis)
269         throws IOException JavaDoc {
270
271         this.timeout = millis;
272         control.setTimeout(millis);
273     }
274
275     /**
276      * Set the connect mode
277      *
278      * @param mode ACTIVE or PASV mode
279      */

280     public void setConnectMode(FTPConnectMode mode) {
281         connectMode = mode;
282     }
283
284     /**
285      * Login into an account on the FTP server. This
286      * call completes the entire login process
287      *
288      * @param user user name
289      * @param password user's password
290      */

291     public void login(String JavaDoc user, String JavaDoc password)
292         throws IOException JavaDoc, FTPException {
293
294         String JavaDoc response = control.sendCommand("USER " + user);
295         lastValidReply = control.validateReply(response, "331");
296         response = control.sendCommand("PASS " + password);
297         lastValidReply = control.validateReply(response, "230");
298     }
299
300
301     /**
302      * Supply the user name to log into an account
303      * on the FTP server. Must be followed by the
304      * password() method - but we allow for
305      *
306      * @param user user name
307      * @param password user's password
308      */

309     public void user(String JavaDoc user)
310         throws IOException JavaDoc, FTPException {
311
312         String JavaDoc reply = control.sendCommand("USER " + user);
313
314         // we allow for a site with no password - 230 response
315
String JavaDoc[] validCodes = {"230", "331"};
316         lastValidReply = control.validateReply(reply, validCodes);
317     }
318
319
320     /**
321      * Supplies the password for a previously supplied
322      * username to log into the FTP server. Must be
323      * preceeded by the user() method
324      *
325      * @param user user name
326      * @param password user's password
327      */

328     public void password(String JavaDoc password)
329         throws IOException JavaDoc, FTPException {
330
331         String JavaDoc reply = control.sendCommand("PASS " + password);
332
333         // we allow for a site with no passwords (202)
334
String JavaDoc[] validCodes = {"230", "202"};
335         lastValidReply = control.validateReply(reply, validCodes);
336     }
337
338     /**
339      * Set up SOCKS v4/v5 proxy settings. This can be used if there
340      * is a SOCKS proxy server in place that must be connected thru.
341      * Note that setting these properties directs <b>all</b> TCP
342      * sockets in this JVM to the SOCKS proxy
343      *
344      * @param port SOCKS proxy port
345      * @param host SOCKS proxy hostname
346      */

347     public static void initSOCKS(String JavaDoc port, String JavaDoc host) {
348         Properties JavaDoc props = System.getProperties();
349         props.put("socksProxyPort", port);
350         props.put("socksProxyHost", host);
351         System.setProperties(props);
352     }
353
354     /**
355      * Set up SOCKS username and password for SOCKS username/password
356      * authentication. Often, no authentication will be required
357      * but the SOCKS server may be configured to request these.
358      *
359      * @param username the SOCKS username
360      * @param password the SOCKS password
361      */

362     public static void initSOCKSAuthentication(String JavaDoc username,
363                                                String JavaDoc password) {
364         Properties JavaDoc props = System.getProperties();
365         props.put("java.net.socks.username", username);
366         props.put("java.net.socks.password", password);
367         System.setProperties(props);
368     }
369
370     /**
371      * Get the name of the remote host
372      *
373      * @return remote host name
374      */

375     String JavaDoc getRemoteHostName() {
376         return control.getRemoteHostName();
377     }
378
379
380     /**
381      * Issue arbitrary ftp commands to the FTP server.
382      *
383      * @param command ftp command to be sent to server
384      * @param validCodes valid return codes for this command
385      */

386     public void quote(String JavaDoc command, String JavaDoc[] validCodes)
387         throws IOException JavaDoc, FTPException {
388
389         String JavaDoc reply = control.sendCommand(command);
390
391         // allow for no validation to be supplied
392
if (validCodes != null && validCodes.length > 0)
393             lastValidReply = control.validateReply(reply, validCodes);
394     }
395
396
397     /**
398      * Put a local file onto the FTP server. It
399      * is placed in the current directory.
400      *
401      * @param localPath path of the local file
402      * @param remoteFile name of remote file in
403      * current directory
404      */

405     public void put(String JavaDoc localPath, String JavaDoc remoteFile)
406         throws IOException JavaDoc, FTPException {
407
408         put(localPath, remoteFile, false);
409     }
410
411     /**
412      * Put a stream of data onto the FTP server. It
413      * is placed in the current directory.
414      *
415      * @param srcStream input stream of data to put
416      * @param remoteFile name of remote file in
417      * current directory
418      */

419     public void put(InputStream JavaDoc srcStream, String JavaDoc remoteFile)
420         throws IOException JavaDoc, FTPException {
421
422         put(srcStream, remoteFile, false);
423     }
424
425
426     /**
427      * Put a local file onto the FTP server. It
428      * is placed in the current directory. Allows appending
429      * if current file exists
430      *
431      * @param localPath path of the local file
432      * @param remoteFile name of remote file in
433      * current directory
434      * @param append true if appending, false otherwise
435      */

436     public void put(String JavaDoc localPath, String JavaDoc remoteFile,
437                     boolean append)
438         throws IOException JavaDoc, FTPException {
439
440         // get according to set type
441
if (getType() == FTPTransferType.ASCII) {
442             putASCII(localPath, remoteFile, append);
443         }
444         else {
445             putBinary(localPath, remoteFile, append);
446         }
447         validateTransfer();
448      }
449
450     /**
451      * Put a stream of data onto the FTP server. It
452      * is placed in the current directory. Allows appending
453      * if current file exists
454      *
455      * @param srcStream input stream of data to put
456      * @param remoteFile name of remote file in
457      * current directory
458      * @param append true if appending, false otherwise
459      */

460     public void put(InputStream JavaDoc srcStream, String JavaDoc remoteFile,
461                     boolean append)
462         throws IOException JavaDoc, FTPException {
463
464         // get according to set type
465
if (getType() == FTPTransferType.ASCII) {
466             putASCII(srcStream, remoteFile, append);
467         }
468         else {
469             putBinary(srcStream, remoteFile, append);
470         }
471         validateTransfer();
472     }
473
474     /**
475      * Validate that the put() or get() was successful
476      */

477     private void validateTransfer()
478         throws IOException JavaDoc, FTPException {
479
480         // check the control response
481
String JavaDoc[] validCodes = {"226", "250"};
482         String JavaDoc reply = control.readReply();
483         lastValidReply = control.validateReply(reply, validCodes);
484     }
485
486     /**
487      * Request the server to set up the put
488      *
489      * @param remoteFile name of remote file in
490      * current directory
491      * @param append true if appending, false otherwise
492      */

493     private void initPut(String JavaDoc remoteFile, boolean append)
494         throws IOException JavaDoc, FTPException {
495
496         // set up data channel
497
data = control.createDataSocket(connectMode);
498         data.setTimeout(timeout);
499
500         // send the command to store
501
String JavaDoc cmd = append ? "APPE " : "STOR ";
502         String JavaDoc reply = control.sendCommand(cmd + remoteFile);
503
504         // Can get a 125 or a 150
505
String JavaDoc[] validCodes = {"125", "150"};
506         lastValidReply = control.validateReply(reply, validCodes);
507     }
508
509
510     /**
511      * Put as ASCII, i.e. read a line at a time and write
512      * inserting the correct FTP separator
513      *
514      * @param localPath full path of local file to read from
515      * @param remoteFile name of remote file we are writing to
516      * @param append true if appending, false otherwise
517      */

518     private void putASCII(String JavaDoc localPath, String JavaDoc remoteFile, boolean append)
519         throws IOException JavaDoc, FTPException {
520
521         // create an inputstream & pass to common method
522
InputStream JavaDoc srcStream = new FileInputStream JavaDoc(localPath);
523         putASCII(srcStream, remoteFile, append);
524     }
525
526     /**
527      * Put as ASCII, i.e. read a line at a time and write
528      * inserting the correct FTP separator
529      *
530      * @param srcStream input stream of data to put
531      * @param remoteFile name of remote file we are writing to
532      * @param append true if appending, false otherwise
533      */

534     private void putASCII(InputStream JavaDoc srcStream, String JavaDoc remoteFile,
535                           boolean append)
536         throws IOException JavaDoc, FTPException {
537
538         // need to read line by line ...
539
LineNumberReader JavaDoc in
540             = new LineNumberReader JavaDoc(new InputStreamReader JavaDoc(srcStream));
541
542         initPut(remoteFile, append);
543
544         // get an character output stream to write to ... AFTER we
545
// have the ok to go ahead AND AFTER we've successfully opened a
546
// stream for the local file
547
BufferedWriter JavaDoc out =
548             new BufferedWriter JavaDoc(
549                 new OutputStreamWriter JavaDoc(data.getOutputStream()));
550
551         // write line by line, writing \r\n as required by RFC959 after
552
// each line
553
String JavaDoc line = null;
554         while ((line = in.readLine()) != null) {
555             out.write(line, 0, line.length());
556             out.write(FTPControlSocket.EOL, 0, FTPControlSocket.EOL.length());
557         }
558         in.close();
559         out.flush();
560         out.close();
561
562         // and close the data socket
563
try {
564             data.close();
565         }
566         catch (IOException JavaDoc ignore) {}
567     }
568
569
570     /**
571      * Put as binary, i.e. read and write raw bytes
572      *
573      * @param localPath full path of local file to read from
574      * @param remoteFile name of remote file we are writing to
575      * @param append true if appending, false otherwise
576      */

577     private void putBinary(String JavaDoc localPath, String JavaDoc remoteFile,
578                            boolean append)
579         throws IOException JavaDoc, FTPException {
580
581         // open input stream to read source file ... do this
582
// BEFORE opening output stream to server, so if file not
583
// found, an exception is thrown
584
InputStream JavaDoc srcStream = new FileInputStream JavaDoc(localPath);
585         putBinary(srcStream, remoteFile, append);
586     }
587
588     /**
589      * Put as binary, i.e. read and write raw bytes
590      *
591      * @param srcStream input stream of data to put
592      * @param remoteFile name of remote file we are writing to
593      * @param append true if appending, false otherwise
594      */

595     private void putBinary(InputStream JavaDoc srcStream, String JavaDoc remoteFile,
596                            boolean append)
597         throws IOException JavaDoc, FTPException {
598
599         BufferedInputStream JavaDoc in =
600             new BufferedInputStream JavaDoc(srcStream);
601
602         initPut(remoteFile, append);
603
604         // get an output stream
605
BufferedOutputStream JavaDoc out =
606             new BufferedOutputStream JavaDoc(
607                 new DataOutputStream JavaDoc(data.getOutputStream()));
608
609         byte[] buf = new byte[512];
610
611         // read a chunk at a time and write to the data socket
612
long size = 0;
613         int count = 0;
614         while ((count = in.read(buf)) > 0) {
615             out.write(buf, 0, count);
616             size += count;
617         }
618         
619         in.close();
620
621         // flush and clean up
622
out.flush();
623         out.close();
624
625         // and close the data socket
626
try {
627             data.close();
628         }
629         catch (IOException JavaDoc ignore) {}
630         
631         // log bytes transferred
632
control.log("Transferred " + size + " bytes to remote host");
633     }
634
635
636     /**
637      * Put data onto the FTP server. It
638      * is placed in the current directory.
639      *
640      * @param data array of bytes
641      * @param remoteFile name of remote file in
642      * current directory
643      */

644     public void put(byte[] bytes, String JavaDoc remoteFile)
645         throws IOException JavaDoc, FTPException {
646
647         put(bytes, remoteFile, false);
648     }
649
650     /**
651      * Put data onto the FTP server. It
652      * is placed in the current directory. Allows
653      * appending if current file exists
654      *
655      * @param data array of bytes
656      * @param remoteFile name of remote file in
657      * current directory
658      * @param append true if appending, false otherwise
659      */

660     public void put(byte[] bytes, String JavaDoc remoteFile, boolean append)
661         throws IOException JavaDoc, FTPException {
662
663         initPut(remoteFile, append);
664
665         // get an output stream
666
BufferedOutputStream JavaDoc out =
667             new BufferedOutputStream JavaDoc(
668                 new DataOutputStream JavaDoc(data.getOutputStream()));
669
670         // write array
671
out.write(bytes, 0, bytes.length);
672
673         // flush and clean up
674
out.flush();
675         out.close();
676
677         // and close the data socket
678
try {
679             data.close();
680         }
681         catch (IOException JavaDoc ignore) {}
682
683         validateTransfer();
684     }
685
686
687     /**
688      * Get data from the FTP server. Uses the currently
689      * set transfer mode.
690      *
691      * @param localPath local file to put data in
692      * @param remoteFile name of remote file in
693      * current directory
694      */

695     public void get(String JavaDoc localPath, String JavaDoc remoteFile)
696         throws IOException JavaDoc, FTPException {
697
698         // get according to set type
699
if (getType() == FTPTransferType.ASCII) {
700             getASCII(localPath, remoteFile);
701         }
702         else {
703             getBinary(localPath, remoteFile);
704         }
705         validateTransfer();
706     }
707
708     /**
709      * Get data from the FTP server. Uses the currently
710      * set transfer mode.
711      *
712      * @param destStream data stream to write data to
713      * @param remoteFile name of remote file in
714      * current directory
715      */

716     public void get(OutputStream JavaDoc destStream, String JavaDoc remoteFile)
717         throws IOException JavaDoc, FTPException {
718
719         // get according to set type
720
if (getType() == FTPTransferType.ASCII) {
721             getASCII(destStream, remoteFile);
722         }
723         else {
724             getBinary(destStream, remoteFile);
725         }
726         validateTransfer();
727     }
728
729
730     /**
731      * Request to the server that the get is set up
732      *
733      * @param remoteFile name of remote file
734      */

735     private void initGet(String JavaDoc remoteFile)
736         throws IOException JavaDoc, FTPException {
737
738         // set up data channel
739
data = control.createDataSocket(connectMode);
740         data.setTimeout(timeout);
741
742         // send the retrieve command
743
String JavaDoc reply = control.sendCommand("RETR " + remoteFile);
744
745         // Can get a 125 or a 150
746
String JavaDoc[] validCodes1 = {"125", "150"};
747         lastValidReply = control.validateReply(reply, validCodes1);
748     }
749
750
751     /**
752      * Get as ASCII, i.e. read a line at a time and write
753      * using the correct newline separator for the OS
754      *
755      * @param localPath full path of local file to write to
756      * @param remoteFile name of remote file
757      */

758     private void getASCII(String JavaDoc localPath, String JavaDoc remoteFile)
759         throws IOException JavaDoc, FTPException {
760
761         // B.McKeown:
762
// Call initGet() before creating the FileOutputStream.
763
// This will prevent being left with an empty file if a FTPException
764
// is thrown by initGet().
765
initGet(remoteFile);
766
767         // B. McKeown: Need to store the local file name so the file can be
768
// deleted if necessary.
769
File JavaDoc localFile = new File JavaDoc(localPath);
770
771         // create the buffered stream for writing
772
BufferedWriter JavaDoc out =
773             new BufferedWriter JavaDoc(
774                 new FileWriter JavaDoc(localPath));
775
776         // get an character input stream to read data from ... AFTER we
777
// have the ok to go ahead AND AFTER we've successfully opened a
778
// stream for the local file
779
LineNumberReader JavaDoc in =
780             new LineNumberReader JavaDoc(
781                 new InputStreamReader JavaDoc(data.getInputStream()));
782
783         // B. McKeown:
784
// If we are in active mode we have to set the timeout of the passive
785
// socket. We can achieve this by calling setTimeout() again.
786
// If we are in passive mode then we are merely setting the value twice
787
// which does no harm anyway. Doing this simplifies any logic changes.
788
data.setTimeout(timeout);
789
790         // read/write a line at a time
791
IOException JavaDoc storedEx = null;
792         String JavaDoc line = null;
793         try {
794             while ((line = in.readLine()) != null) {
795                 out.write(line, 0, line.length());
796                 out.newLine();
797             }
798         }
799         catch (IOException JavaDoc ex) {
800             storedEx = ex;
801             localFile.delete();
802         }
803         finally {
804             out.close();
805         }
806
807         try {
808             in.close();
809             data.close();
810         }
811         catch (IOException JavaDoc ignore) {}
812
813         // if we failed to write the file, rethrow the exception
814
if (storedEx != null)
815             throw storedEx;
816     }
817
818     /**
819      * Get as ASCII, i.e. read a line at a time and write
820      * using the correct newline separator for the OS
821      *
822      * @param destStream data stream to write data to
823      * @param remoteFile name of remote file
824      */

825     private void getASCII(OutputStream JavaDoc destStream, String JavaDoc remoteFile)
826         throws IOException JavaDoc, FTPException {
827
828         initGet(remoteFile);
829
830         // create the buffered stream for writing
831
BufferedWriter JavaDoc out =
832             new BufferedWriter JavaDoc(
833                 new OutputStreamWriter JavaDoc(destStream));
834
835         // get an character input stream to read data from ... AFTER we
836
// have the ok to go ahead
837
LineNumberReader JavaDoc in =
838             new LineNumberReader JavaDoc(
839                 new InputStreamReader JavaDoc(data.getInputStream()));
840
841         // B. McKeown:
842
// If we are in active mode we have to set the timeout of the passive
843
// socket. We can achieve this by calling setTimeout() again.
844
// If we are in passive mode then we are merely setting the value twice
845
// which does no harm anyway. Doing this simplifies any logic changes.
846
data.setTimeout(timeout);
847
848         // read/write a line at a time
849
IOException JavaDoc storedEx = null;
850         String JavaDoc line = null;
851         try {
852             while ((line = in.readLine()) != null) {
853                 out.write(line, 0, line.length());
854                 out.newLine();
855             }
856         }
857         catch (IOException JavaDoc ex) {
858             storedEx = ex;
859         }
860         finally {
861             out.close();
862         }
863
864         try {
865             in.close();
866             data.close();
867         }
868         catch (IOException JavaDoc ignore) {}
869
870         // if we failed to write the file, rethrow the exception
871
if (storedEx != null)
872             throw storedEx;
873     }
874
875
876     /**
877      * Get as binary file, i.e. straight transfer of data
878      *
879      * @param localPath full path of local file to write to
880      * @param remoteFile name of remote file
881      */

882     private void getBinary(String JavaDoc localPath, String JavaDoc remoteFile)
883         throws IOException JavaDoc, FTPException {
884
885         // B.McKeown:
886
// Call initGet() before creating the FileOutputStream.
887
// This will prevent being left with an empty file if a FTPException
888
// is thrown by initGet().
889
initGet(remoteFile);
890
891         // B. McKeown: Need to store the local file name so the file can be
892
// deleted if necessary.
893
File JavaDoc localFile = new File JavaDoc(localPath);
894
895         // create the buffered output stream for writing the file
896
BufferedOutputStream JavaDoc out =
897             new BufferedOutputStream JavaDoc(
898                 new FileOutputStream JavaDoc(localPath, false));
899
900         // get an input stream to read data from ... AFTER we have
901
// the ok to go ahead AND AFTER we've successfully opened a
902
// stream for the local file
903
BufferedInputStream JavaDoc in =
904             new BufferedInputStream JavaDoc(
905                 new DataInputStream JavaDoc(data.getInputStream()));
906
907         // B. McKeown:
908
// If we are in active mode we have to set the timeout of the passive
909
// socket. We can achieve this by calling setTimeout() again.
910
// If we are in passive mode then we are merely setting the value twice
911
// which does no harm anyway. Doing this simplifies any logic changes.
912
data.setTimeout(timeout);
913
914         // do the retrieving
915
long size = 0;
916         int chunksize = 4096;
917         byte [] chunk = new byte[chunksize];
918         int count;
919         IOException JavaDoc storedEx = null;
920
921         // read from socket & write to file in chunks
922
try {
923             while ((count = in.read(chunk, 0, chunksize)) >= 0) {
924                 out.write(chunk, 0, count);
925                 size += count;
926             }
927         }
928         catch (IOException JavaDoc ex) {
929             storedEx = ex;
930             localFile.delete();
931         }
932         finally {
933             out.close();
934         }
935
936         // close streams
937
try {
938             in.close();
939             data.close();
940         }
941         catch (IOException JavaDoc ignore) {}
942
943         // if we failed to write the file, rethrow the exception
944
if (storedEx != null)
945             throw storedEx;
946             
947         // log bytes transferred
948
control.log("Transferred " + size + " bytes from remote host");
949     }
950
951     /**
952      * Get as binary file, i.e. straight transfer of data
953      *
954      * @param destStream stream to write to
955      * @param remoteFile name of remote file
956      */

957     private void getBinary(OutputStream JavaDoc destStream, String JavaDoc remoteFile)
958         throws IOException JavaDoc, FTPException {
959
960         initGet(remoteFile);
961
962         // create the buffered output stream for writing the file
963
BufferedOutputStream JavaDoc out =
964             new BufferedOutputStream JavaDoc(destStream);
965
966         // get an input stream to read data from ... AFTER we have
967
// the ok to go ahead AND AFTER we've successfully opened a
968
// stream for the local file
969
BufferedInputStream JavaDoc in =
970             new BufferedInputStream JavaDoc(
971                 new DataInputStream JavaDoc(data.getInputStream()));
972
973         // B. McKeown:
974
// If we are in active mode we have to set the timeout of the passive
975
// socket. We can achieve this by calling setTimeout() again.
976
// If we are in passive mode then we are merely setting the value twice
977
// which does no harm anyway. Doing this simplifies any logic changes.
978
data.setTimeout(timeout);
979
980         // do the retrieving
981
long size = 0;
982         int chunksize = 4096;
983         byte [] chunk = new byte[chunksize];
984         int count;
985         IOException JavaDoc storedEx = null;
986
987         // read from socket & write to file in chunks
988
try {
989             while ((count = in.read(chunk, 0, chunksize)) >= 0) {
990                 out.write(chunk, 0, count);
991                 size += count;
992             }
993         }
994         catch (IOException JavaDoc ex) {
995             storedEx = ex;
996         }
997         finally {
998             out.close();
999         }
1000
1001        // close streams
1002
try {
1003            in.close();
1004            data.close();
1005        }
1006        catch (IOException JavaDoc ignore) {}
1007
1008        // if we failed to write to the stream, rethrow the exception
1009
if (storedEx != null)
1010            throw storedEx;
1011            
1012        // log bytes transferred
1013
control.log("Transferred " + size + " bytes from remote host");
1014    }
1015
1016
1017    /**
1018     * Get data from the FTP server. Transfers in
1019     * whatever mode we are in. Retrieve as a byte array. Note
1020     * that we may experience memory limitations as the
1021     * entire file must be held in memory at one time.
1022     *
1023     * @param remoteFile name of remote file in
1024     * current directory
1025     */

1026    public byte[] get(String JavaDoc remoteFile)
1027        throws IOException JavaDoc, FTPException {
1028
1029        initGet(remoteFile);
1030
1031        // get an input stream to read data from
1032
BufferedInputStream JavaDoc in =
1033            new BufferedInputStream JavaDoc(
1034                new DataInputStream JavaDoc(data.getInputStream()));
1035
1036        // B. McKeown:
1037
// If we are in active mode we have to set the timeout of the passive
1038
// socket. We can achieve this by calling setTimeout() again.
1039
// If we are in passive mode then we are merely setting the value twice
1040
// which does no harm anyway. Doing this simplifies any logic changes.
1041
data.setTimeout(timeout);
1042
1043        // do the retrieving
1044
int chunksize = 4096;
1045        byte [] chunk = new byte[chunksize]; // read chunks into
1046
byte [] resultBuf = null; // where we place result
1047
ByteArrayOutputStream JavaDoc temp =
1048            new ByteArrayOutputStream JavaDoc(chunksize); // temp swap buffer
1049
int count; // size of chunk read
1050

1051        // read from socket & write to file
1052
while ((count = in.read(chunk, 0, chunksize)) >= 0) {
1053            temp.write(chunk, 0, count);
1054        }
1055        temp.close();
1056
1057        // get the bytes from the temp buffer
1058
resultBuf = temp.toByteArray();
1059
1060        // close streams
1061
try {
1062            in.close();
1063            data.close();
1064        }
1065        catch (IOException JavaDoc ignore) {}
1066        
1067        validateTransfer();
1068
1069        return resultBuf;
1070    }
1071
1072
1073    /**
1074     * Run a site-specific command on the
1075     * server. Support for commands is dependent
1076     * on the server
1077     *
1078     * @param command the site command to run
1079     * @return true if command ok, false if
1080     * command not implemented
1081     */

1082    public boolean site(String JavaDoc command)
1083        throws IOException JavaDoc, FTPException {
1084
1085        // send the retrieve command
1086
String JavaDoc reply = control.sendCommand("SITE " + command);
1087
1088        // Can get a 200 (ok) or 202 (not impl). Some
1089
// FTP servers return 502 (not impl)
1090
String JavaDoc[] validCodes = {"200", "202", "502"};
1091        lastValidReply = control.validateReply(reply, validCodes);
1092
1093        // return true or false? 200 is ok, 202/502 not
1094
// implemented
1095
if (reply.substring(0, 3).equals("200"))
1096            return true;
1097        else
1098            return false;
1099    }
1100
1101
1102    /**
1103     * List a directory's contents
1104     *
1105     * @param dirname the name of the directory (<b>not</b> a file mask)
1106     * @return a string containing the line separated
1107     * directory listing
1108     * @deprecated As of FTP 1.1, replaced by {@link #dir(String)}
1109     */

1110    public String JavaDoc list(String JavaDoc dirname)
1111        throws IOException JavaDoc, FTPException {
1112
1113        return list(dirname, false);
1114    }
1115
1116
1117    /**
1118     * List a directory's contents as one string. A detailed
1119     * listing is available, otherwise just filenames are provided.
1120     * The detailed listing varies in details depending on OS and
1121     * FTP server.
1122     *
1123     * @param dirname the name of the directory(<b>not</b> a file mask)
1124     * @param full true if detailed listing required
1125     * false otherwise
1126     * @return a string containing the line separated
1127     * directory listing
1128     * @deprecated As of FTP 1.1, replaced by {@link #dir(String,boolean)}
1129     */

1130    public String JavaDoc list(String JavaDoc dirname, boolean full)
1131        throws IOException JavaDoc, FTPException {
1132
1133        String JavaDoc[] list = dir(dirname, full);
1134
1135        StringBuffer JavaDoc result = new StringBuffer JavaDoc();
1136        String JavaDoc sep = System.getProperty("line.separator");
1137
1138        // loop thru results and make into one string
1139
for (int i = 0; i < list.length; i++) {
1140            result.append(list[i]);
1141            result.append(sep);
1142        }
1143
1144        return result.toString();
1145    }
1146
1147    /**
1148     * List current directory's contents as an array of strings of
1149     * filenames.
1150     *
1151     * @return an array of current directory listing strings
1152     */

1153    public String JavaDoc[] dir()
1154        throws IOException JavaDoc, FTPException {
1155
1156        return dir(null, false);
1157    }
1158
1159    /**
1160     * List a directory's contents as an array of strings of filenames.
1161     *
1162     * @param dirname name of directory(<b>not</b> a file mask)
1163     * @return an array of directory listing strings
1164     */

1165    public String JavaDoc[] dir(String JavaDoc dirname)
1166        throws IOException JavaDoc, FTPException {
1167
1168        return dir(dirname, false);
1169    }
1170
1171
1172    /**
1173     * List a directory's contents as an array of strings. A detailed
1174     * listing is available, otherwise just filenames are provided.
1175     * The detailed listing varies in details depending on OS and
1176     * FTP server. Note that a full listing can be used on a file
1177     * name to obtain information about a file
1178     *
1179     * @param dirname name of directory (<b>not</b> a file mask)
1180     * @param full true if detailed listing required
1181     * false otherwise
1182     * @return an array of directory listing strings
1183     */

1184    public String JavaDoc[] dir(String JavaDoc dirname, boolean full)
1185        throws IOException JavaDoc, FTPException {
1186
1187        // set up data channel
1188
data = control.createDataSocket(connectMode);
1189        data.setTimeout(timeout);
1190
1191        // send the retrieve command
1192
String JavaDoc command = full ? "LIST ":"NLST ";
1193        if (dirname != null)
1194            command += dirname;
1195
1196        // some FTP servers bomb out if NLST has whitespace appended
1197
command = command.trim();
1198        String JavaDoc reply = control.sendCommand(command);
1199
1200        // check the control response. wu-ftp returns 550 if the
1201
// directory is empty, so we handle 550 appropriately. Similarly
1202
// proFTPD returns 450
1203
String JavaDoc[] validCodes1 = {"125", "150", "450", "550"};
1204        lastValidReply = control.validateReply(reply, validCodes1);
1205
1206        // an empty array of files for 450/550
1207
String JavaDoc[] result = new String JavaDoc[0];
1208
1209        // a normal reply ... extract the file list
1210
String JavaDoc replyCode = lastValidReply.getReplyCode();
1211        if (!replyCode.equals("450") && !replyCode.equals("550")) {
1212            // get an character input stream to read data from .
1213
LineNumberReader JavaDoc in =
1214                new LineNumberReader JavaDoc(
1215                     new InputStreamReader JavaDoc(data.getInputStream()));
1216
1217            // read a line at a time
1218
Vector JavaDoc lines = new Vector JavaDoc();
1219            String JavaDoc line = null;
1220            while ((line = in.readLine()) != null) {
1221                lines.add(line);
1222            }
1223            try {
1224                in.close();
1225                data.close();
1226            }
1227            catch (IOException JavaDoc ignore) {}
1228                
1229            // check the control response
1230
String JavaDoc[] validCodes2 = {"226", "250"};
1231            reply = control.readReply();
1232            lastValidReply = control.validateReply(reply, validCodes2);
1233
1234            // empty array is default
1235
if (!lines.isEmpty())
1236                result = (String JavaDoc[])lines.toArray(result);
1237        }
1238        return result;
1239    }
1240
1241    /**
1242     * Gets the latest valid reply from the server
1243     *
1244     * @return reply object encapsulating last valid server response
1245     */

1246    public FTPReply getLastValidReply() {
1247        return lastValidReply;
1248    }
1249
1250
1251    /**
1252     * Switch debug of responses on or off
1253     *
1254     * @param on true if you wish to have responses to
1255     * the log stream, false otherwise
1256     */

1257    public void debugResponses(boolean on) {
1258        control.debugResponses(on);
1259    }
1260
1261     /**
1262      * Set the logging stream, replacing
1263      * stdout
1264      *
1265      * @param log the new logging stream
1266      */

1267     public void setLogStream(PrintWriter JavaDoc log) {
1268         control.setLogStream(log);
1269     }
1270
1271    /**
1272     * Get the current transfer type
1273     *
1274     * @return the current type of the transfer,
1275     * i.e. BINARY or ASCII
1276     */

1277    public FTPTransferType getType() {
1278        return transferType;
1279    }
1280
1281    /**
1282     * Set the transfer type
1283     *
1284     * @param type the transfer type to
1285     * set the server to
1286     */

1287    public void setType(FTPTransferType type)
1288        throws IOException JavaDoc, FTPException {
1289
1290        // determine the character to send
1291
String JavaDoc typeStr = FTPTransferType.ASCII_CHAR;
1292        if (type.equals(FTPTransferType.BINARY))
1293            typeStr = FTPTransferType.BINARY_CHAR;
1294
1295        // send the command
1296
String JavaDoc reply = control.sendCommand("TYPE " + typeStr);
1297        lastValidReply = control.validateReply(reply, "200");
1298
1299        // record the type
1300
transferType = type;
1301    }
1302
1303
1304    /**
1305     * Delete the specified remote file
1306     *
1307     * @param remoteFile name of remote file to
1308     * delete
1309     */

1310    public void delete(String JavaDoc remoteFile)
1311        throws IOException JavaDoc, FTPException {
1312
1313        String JavaDoc reply = control.sendCommand("DELE " + remoteFile);
1314        lastValidReply = control.validateReply(reply, "250");
1315    }
1316
1317
1318    /**
1319     * Rename a file or directory
1320     *
1321     * @param from name of file or directory to rename
1322     * @param to intended name
1323     */

1324    public void rename(String JavaDoc from, String JavaDoc to)
1325        throws IOException JavaDoc, FTPException {
1326
1327        String JavaDoc reply = control.sendCommand("RNFR " + from);
1328        lastValidReply = control.validateReply(reply, "350");
1329
1330        reply = control.sendCommand("RNTO " + to);
1331        lastValidReply = control.validateReply(reply, "250");
1332    }
1333
1334
1335    /**
1336     * Delete the specified remote working directory
1337     *
1338     * @param dir name of remote directory to
1339     * delete
1340     */

1341    public void rmdir(String JavaDoc dir)
1342        throws IOException JavaDoc, FTPException {
1343
1344        String JavaDoc reply = control.sendCommand("RMD " + dir);
1345
1346        // some servers return 257, technically incorrect but
1347
// we cater for it ...
1348
String JavaDoc[] validCodes = {"250", "257"};
1349        lastValidReply = control.validateReply(reply, validCodes);
1350    }
1351
1352
1353    /**
1354     * Create the specified remote working directory
1355     *
1356     * @param dir name of remote directory to
1357     * create
1358     */

1359    public void mkdir(String JavaDoc dir)
1360        throws IOException JavaDoc, FTPException {
1361
1362        String JavaDoc reply = control.sendCommand("MKD " + dir);
1363        lastValidReply = control.validateReply(reply, "257");
1364    }
1365
1366
1367    /**
1368     * Change the remote working directory to
1369     * that supplied
1370     *
1371     * @param dir name of remote directory to
1372     * change to
1373     */

1374    public void chdir(String JavaDoc dir)
1375        throws IOException JavaDoc, FTPException {
1376
1377        String JavaDoc reply = control.sendCommand("CWD " + dir);
1378        lastValidReply = control.validateReply(reply, "250");
1379    }
1380
1381    /**
1382     * Get modification time for a remote file
1383     *
1384     * @param remoteFile name of remote file
1385     * @return modification time of file as a date
1386     */

1387    public Date JavaDoc modtime(String JavaDoc remoteFile)
1388        throws IOException JavaDoc, FTPException {
1389
1390        String JavaDoc reply = control.sendCommand("MDTM " + remoteFile);
1391        lastValidReply = control.validateReply(reply, "213");
1392
1393        // parse the reply string ...
1394
Date JavaDoc ts = tsFormat.parse(lastValidReply.getReplyText(),
1395                                 new ParsePosition JavaDoc(0));
1396        return ts;
1397    }
1398
1399    /**
1400     * Get the current remote working directory
1401     *
1402     * @return the current working directory
1403     */

1404    public String JavaDoc pwd()
1405        throws IOException JavaDoc, FTPException {
1406
1407        String JavaDoc reply = control.sendCommand("PWD");
1408        lastValidReply = control.validateReply(reply, "257");
1409
1410        // get the reply text and extract the dir
1411
// listed in quotes, if we can find it. Otherwise
1412
// just return the whole reply string
1413
String JavaDoc text = lastValidReply.getReplyText();
1414        int start = text.indexOf('"');
1415        int end = text.lastIndexOf('"');
1416        if (start >= 0 && end > start)
1417            return text.substring(start+1, end);
1418        else
1419            return text;
1420    }
1421
1422    /**
1423     * Get the type of the OS at the server
1424     *
1425     * @return the type of server OS
1426     */

1427    public String JavaDoc system()
1428        throws IOException JavaDoc, FTPException {
1429
1430        String JavaDoc reply = control.sendCommand("SYST");
1431        lastValidReply = control.validateReply(reply, "215");
1432        return lastValidReply.getReplyText();
1433    }
1434
1435    /**
1436     * Get the help text for the specified command
1437     *
1438     * @param command name of the command to get help on
1439     * @return help text from the server for the supplied command
1440     */

1441    public String JavaDoc help(String JavaDoc command)
1442        throws IOException JavaDoc, FTPException {
1443
1444        String JavaDoc reply = control.sendCommand("HELP " + command);
1445        String JavaDoc[] validCodes = {"211", "214"};
1446        lastValidReply = control.validateReply(reply, validCodes);
1447        return lastValidReply.getReplyText();
1448    }
1449
1450    /**
1451     * Quit the FTP session
1452     *
1453     */

1454    public void quit()
1455        throws IOException JavaDoc, FTPException {
1456
1457        try {
1458            String JavaDoc reply = control.sendCommand("QUIT");
1459            String JavaDoc[] validCodes = {"221", "226"};
1460            lastValidReply = control.validateReply(reply, validCodes);
1461        }
1462        finally { // ensure we clean up the connection
1463
control.logout();
1464            control = null;
1465        }
1466    }
1467
1468}
1469
1470
1471
1472
Popular Tags