Source code: org/finj/FTPClient.java
1 package org.finj;
2
3 import java.io.BufferedReader;
4 import java.io.InputStream;
5 import java.io.InputStreamReader;
6 import java.io.IOException;
7 import java.io.OutputStream;
8 import java.io.OutputStreamWriter;
9 import java.io.PrintWriter;
10
11 import java.net.InetAddress;
12 import java.net.ServerSocket;
13 import java.net.Socket;
14 import java.net.UnknownHostException;
15
16 import java.util.Locale;
17
18 import org.finj.FTPClientObserver;
19 import org.finj.FTPException;
20 import org.finj.RemoteFile;
21
22 // DEPRECATED imports -- kept for "sun.net.ftp.FtpClient" backcompatibility
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import sun.net.ftp.FtpClient;
26 import sun.net.TelnetInputStream;
27 import sun.net.TelnetOutputStream;
28
29 /**
30 *
31 *
32 *
33 *
34 * FIXME : mention default values.
35 *
36 * @author Javier Iglesias -- jiglesias@users.sourceforge.net
37 * @version $Id$
38 */
39 public class FTPClient extends Object {
40
41 /**
42 * Default <CODE>Locale</CODE> used when none is provided
43 * at construction time.
44 *
45 * @since v1.0
46 */
47 public static final Locale DEFAULT_LOCALE = new Locale ("en", "US");
48
49
50 /**
51 * Default FTP port value is '21'.
52 *
53 * @see "RFC959-??"
54 * @since v1.0
55 */
56 public static final int DEFAULT_FTP_PORT = 21;
57
58
59
60 // ----- DATA TYPES -----
61 /**
62 * Default transfer type, intended primarily for the
63 * transfer of text files except when both hosts would
64 * find EBCDIC more convenient.
65 *
66 * @see "RFC959-3:1:1:1"
67 * @since v1.0
68 */
69 public static final int ASCII_DATA_TYPE = 100;
70 /**
71 * Intended for efficient transfer between hosts which
72 * use EBCDIC for their internal character representation.
73 *
74 * @see "RFC959-3:1:1:2"
75 * @since v1.0
76 */
77 public static final int EBCDIC_DATA_TYPE = 101;
78 /**
79 * Data are sent as contiguous bits which, for transfer,
80 * are packed into the 8-bit transfer bytes.
81 *
82 * [API DISCUSSION : wouldn't you prefer 'BINARY_DATA_TYPE']
83 *
84 * @see "RFC959-3:1:1:3"
85 * @since v1.0
86 */
87 public static final int IMAGE_DATA_TYPE = 102;
88 /**
89 * Data is transferred in logical bytes of the size
90 * specified by the obligatory sceond parameter, Byte size.
91 *
92 * @see "RFC959-3:1:1:4"
93 * @since v1.0
94 */
95 public static final int LOCAL_DATA_TYPE = 103;
96
97
98
99
100
101 // ----- DATA STRUCTURES -----
102 /**
103 * Default structure assumed if the <CODE>setTransferStructure</CODE>
104 * has not been used. There is no internal structure and the
105 * file is considered to be a continuous sequence of data bytes.
106 *
107 * @see "RFC959-3:1:2:1"
108 * @since v1.0
109 */
110 public static final int FILE_DATA_STRUCTURE = 200;
111 /**
112 * Record structures must be accepted for "text" files
113 * (i.e., files with ASCII or EBCDIC types) by all FTP
114 * implementations.
115 *
116 * @see "RFC959-3:1:2:2"
117 * @since v1.0
118 */
119 public static final int RECORD_DATA_STRUCTURE = 201;
120 /**
121 * To transmit files that are discontinuous, FTP defines a
122 * page structure. File of this type are sometimes known as
123 * "random access files" or even as "holey files".
124 * In these files there is sometimes other information
125 * associated with the file as a whole (e.g., a file descriptor),
126 * or with a section of the file (e.g., page access controls),
127 * or both. In FTP, the sections of the file are called pages.
128 * each page is sent with a page header.
129 *
130 * @see "RFC959-3:1:2:3"
131 * @since v1.0
132 */
133 public static final int PAGE_DATA_STRUCTURE = 202;
134
135
136
137
138
139 // ----- DATA TRANSMISSION MODES -----
140 /**
141 * The data is transmitted as a stream of bytes. There is no
142 * restriction on the representation type used; record structures
143 * are allowed.
144 *
145 * @see "RFC959-3:4:1"
146 * @since v1.0
147 */
148 public static final int STREAM_DATA_TRANSMISSION_MODE = 300;
149 /**
150 * The file is transmitted as a series of data blocks preceded
151 * by one or more header bytes. Record structures are allowed
152 * in this mode, and any representation type may be used.
153 *
154 * @see "RFC959-3:4:2"
155 * @since v1.0
156 */
157 public static final int BLOCK_DATA_TRANSMISSION_MODE = 301;
158 /**
159 * There are three kinds of information to be sent : regular
160 * data, sent in a byte string; compressed data, consisting
161 * of replications or filler; and control information, sent in
162 * a two-byte escape sequence. Compressed mode is useful for
163 * obtaining increased bandwidth on very large netword
164 * transmissions at a litle extra CPU cost. It can be most
165 * effectively used to reduce the size of printer files such
166 * as those generated by RJE hosts.
167 *
168 * @see "RFC959-3:4:3"
169 * @since v1.0
170 */
171 public static final int COMPRESSED_DATA_TRANSMISSION_MODE = 302;
172
173
174
175
176 /** constant used to differentiate between upload traffic and download traffic */
177 private static final int UPLOAD_TRANSFER = 1;
178 /** constant used to differentiate between upload traffic and download traffic */
179 private static final int DOWNLOAD_TRANSFER = 2;
180
181
182 // ----- PRIVATE GLOBAL VARIABLES -----
183 private FTPClientObserver observer = null; // observer of this (if any)
184 private InetAddress serverhost = null; // IP address of currently opened FTP server
185 private InetAddress localhost = null;
186 private int control_port = DEFAULT_FTP_PORT; // port used for control connection to server
187 // FIXME : what is the default dataPort value ?
188 private byte[] dataHost = null; // IP number used for data connection to server // FIXME : isn't that useless ??
189 private byte[] dataPort = null; // data port used for data connection to server // FIXME : isn't that useless ??
190 private int dataType = IMAGE_DATA_TYPE; // default data type transfered
191 // FIxME : what is the data type length default value ?
192 private int dataTypeLength = 8; // default data type length in bytes : only usefull for LOCAL mode
193 private int dataMode = STREAM_DATA_TRANSMISSION_MODE; // default data transmission
194 private int dataStructure = FILE_DATA_STRUCTURE; // default data structure manipulated
195 private boolean connected = false; // connection status
196
197 // stream handlers
198 private BufferedReader ctrlIn = null;
199 private PrintWriter ctrlOut = null;
200 private InputStream dataIn = null;
201 private OutputStream dataOut = null;
202
203 // about internationalization
204 private Locale locale = null;
205
206
207
208
209
210
211
212
213 // ----- CONSTRUCTORS -----
214 /**
215 * Constructs a new instance of this class.
216 *
217 * @since v1.0
218 */
219 public FTPClient ( ) {
220 this (DEFAULT_LOCALE);
221 }
222 // DONE TESTED
223
224 /**
225 * Constructs a new instance of this class using the
226 * provided <CODE>Locale</CODE> for internationalization
227 * of <CODE>FTPReply</CODE>s... if avaiable.
228 *
229 * Talking about availability, if you have some time (ca. 10 minutes !)
230 * you might translate the 40 (!) sentences into your own language.
231 * Just e-mail me to jiglesias@users.sourceforge.net. MANY THANKS IN ADVANCE !
232 *
233 * @param locale used for internationalization of <CODE>FTPReply</CODE> messages.
234 * @since v1.0
235 */
236 public FTPClient ( Locale locale ) {
237 this.locale = locale;
238 }
239 // DONE TESTED
240
241 /**
242 * Constructs a new instance of this class that
243 * will try to connect to the <CODE>server</CODE>
244 * through the <CODE>DEFAULT_FTP_PORT</CODE>.
245 *
246 * @param server DNS name or IP number of the FTP server to connect to.
247 * @exception IOException something goes wrong with
248 * the sockets, streams, ...
249 * @exception FTPException FTP server is not available
250 * or refuses connections.
251 * @since v1.0
252 */
253 public FTPClient ( String server ) throws IOException, FTPException {
254 this (server, DEFAULT_FTP_PORT, DEFAULT_LOCALE);
255 }
256 // DONE TESTED
257
258 /**
259 * Constructs a new instance of this class that
260 * will try to connect to the <CODE>server</CODE>
261 * through the <CODE>DEFAULT_FTP_PORT</CODE>.
262 *
263 * @param server DNS name or IP number of the FTP server to connect to.
264 * @param locale used for internationalization of <CODE>FTPReply</CODE> messages.
265 * @exception IOException something goes wrong with
266 * the sockets, streams, ...
267 * @exception FTPException FTP server is not available
268 * or refuses connections.
269 * @since v1.0
270 */
271 public FTPClient ( String server,
272 Locale locale ) throws IOException, FTPException {
273 this (server, DEFAULT_FTP_PORT, DEFAULT_LOCALE);
274 }
275 // DONE TESTED
276
277 /**
278 * Constructs a new instance of this class that
279 * will try to connect to the <CODE>server</CODE>
280 * througn the provided <CODE>port</CODE>.
281 *
282 * @param server DNS name or IP number of the FTP server to connect to.
283 * @param port TCP port number to use for the control connection.
284 * @exception IOException something goes wrong with
285 * the sockets, streams, ...
286 * @exception FTPException FTP server is not available
287 * or refuses connections.
288 * @since v1.0
289 */
290 public FTPClient ( String server,
291 int port ) throws IOException, FTPException {
292 this (server, port, DEFAULT_LOCALE);
293 }
294 // DONE TESTED
295
296 /**
297 * Constructs a new instance of this class that
298 * will try to connect to the <CODE>server</CODE>
299 * througn the provided <CODE>port</CODE>.
300 *
301 * @param server DNS name or IP number of the FTP server to connect to.
302 * @param port TCP port number to use for the control connection.
303 * @param locale used for internationalization of <CODE>FTPReply</CODE> messages.
304 * @exception IOException something goes wrong with
305 * the sockets, streams, ...
306 * @exception FTPException FTP server is not available
307 * or refuses connections.
308 * @since v1.0
309 */
310 public FTPClient ( String server,
311 int port,
312 Locale locale ) throws IOException, FTPException {
313 // all constructors (except parameterless and 'Locale-only' ones) call this constructor
314 this.locale = locale;
315 open (server, port);
316 }
317 // DONE TESTED
318
319 /**
320 * Constructs a new instance of this class that
321 * will try to connect to the <CODE>server</CODE>
322 * through the <CODE>DEFAULT_FTP_PORT</CODE>, and try
323 * to log in using <CODE>user</CODE> and <CODE>pass</CODE>
324 * login information.
325 *
326 * @param server DNS name or IP number of the FTP server to connect to.
327 * @param user User name indentifier to use to log in.
328 * @param pass Password to use to log in.
329 * @exception IOException something goes wrong with
330 * the sockets, streams, ...
331 * @exception FTPException FTP server is not available,
332 * refuses connections or login information.
333 * @since v1.0
334 */
335 public FTPClient ( String server,
336 String user,
337 String pass ) throws IOException, FTPException {
338 this (server, DEFAULT_FTP_PORT, user, pass, DEFAULT_LOCALE);
339 }
340 // DONE TESTED
341
342 /**
343 * Constructs a new instance of this class that
344 * will try to connect to the <CODE>server</CODE>
345 * through the <CODE>DEFAULT_FTP_PORT</CODE>, and try
346 * to log in using <CODE>user</CODE> and <CODE>pass</CODE>
347 * login information.
348 *
349 * @param server DNS name or IP number of the FTP server to connect to.
350 * @param user User name indentifier to use to log in.
351 * @param pass Password to use to log in.
352 * @param locale used for internationalization of <CODE>FTPReply</CODE> messages.
353 * @exception IOException something goes wrong with
354 * the sockets, streams, ...
355 * @exception FTPException FTP server is not available,
356 * refuses connections or login information.
357 * @since v1.0
358 */
359 public FTPClient ( String server,
360 String user,
361 String pass,
362 Locale locale ) throws IOException, FTPException {
363 this (server, DEFAULT_FTP_PORT, user, pass, locale);
364 }
365 // DONE TESTED
366
367 /**
368 * Constructs a new instance of this class that
369 * will try to connect to the <CODE>server</CODE>
370 * through the provided <CODE>port</CODE>, and try
371 * to log in using <CODE>user</CODE> and <CODE>pass</CODE>
372 * login information.
373 *
374 * @param server DNS name or IP number of the FTP server to connect to.
375 * @param port TCP port number to use for the control connection.
376 * @param user User name indentifier to use to log in.
377 * @param pass Password to use to log in.
378 * @exception IOException something goes wrong with
379 * the sockets, streams, ...
380 * @exception FTPException FTP server is not available,
381 * refuses connections or login information.
382 * @since v1.0
383 */
384 public FTPClient ( String server,
385 int port,
386 String user,
387 String pass ) throws IOException, FTPException {
388 this (server, port, user, pass, DEFAULT_LOCALE);
389 }
390 // DONE TESTED
391
392 /**
393 * Constructs a new instance of this class that
394 * will try to connect to the <CODE>server</CODE>
395 * through the provided <CODE>port</CODE>, and try
396 * to log in using <CODE>user</CODE> and <CODE>pass</CODE>
397 * login information.
398 *
399 * @param server DNS name or IP number of the FTP server to connect to.
400 * @param port TCP port number to use for the control connection.
401 * @param user User name indentifier to use to log in.
402 * @param pass Password to use to log in.
403 * @param locale used for internationalization of <CODE>FTPReply</CODE> messages.
404 * @exception IOException something goes wrong with
405 * the sockets, streams, ...
406 * @exception FTPException FTP server is not available,
407 * refuses connections or login information.
408 * @since v1.0
409 */
410 public FTPClient ( String server,
411 int port,
412 String user,
413 String pass,
414 Locale locale ) throws IOException, FTPException {
415 this (server, port, locale);
416 login (user, pass);
417 }
418 // DONE TESTED
419
420
421
422
423
424
425
426
427 // ----- ABOUT OBSERVER -----
428
429 /**
430 * Sets the observer of this object to be the one passed as
431 * parameter.
432 *
433 * In order to keep the class thread safe (and because I
434 * don't see any reason to have more than one observer),
435 * only one <CODE>FTPClientObserver</CODE> is allowed per
436 * <CODE>FTPClient</CODE>
437 *
438 * @see FTPClient#hasObserver()
439 * @see FTPClient#getObserver()
440 * @see FTPClient#removeObserver()
441 * @param observer new observer for this instance.
442 * @since v1.0
443 */
444 public void setObserver ( FTPClientObserver observer ) {
445 if ( hasObserver () ) {
446 synchronized (this.observer) {
447 // say 'good bye' to previous observer...
448 this.observer.isObserving (false);
449 // ... set new observer...
450 this.observer = observer;
451 // say 'hello' to new observer
452 this.observer.isObserving (true);
453 }
454 } else {
455 synchronized (observer) {
456 this.observer = observer;
457 observer.isObserving (true);
458 }
459 }
460 }
461 // DONE
462
463 /**
464 * Tells if this instance is currently being observed.
465 *
466 * @see FTPClient#setObserver(FTPClientObserver)
467 * @see FTPClient#getObserver()
468 * @see FTPClient#removeObserver()
469 * @return <CODE>true</CODE> if <CODE>this</CODE> is being
470 * observed.
471 * @since v1.0
472 */
473 public boolean hasObserver ( ) {
474 return (observer != null);
475 }
476 // DONE TESTED
477
478 /**
479 * Returns the current observer of this instance.
480 *
481 * In order to keep the class thread safe (and because I
482 * don't see any reason to have more than one observer),
483 * only one <CODE>FTPClientObserver</CODE> is allowed per
484 * <CODE>FTPClient</CODE>
485 *
486 * @see FTPClient#setObserver(FTPClientObserver)
487 * @see FTPClient#hasObserver()
488 * @see FTPClient#removeObserver()
489 * @return current observer for this instance.
490 * @since v1.0
491 */
492 public FTPClientObserver getObserver ( ) {
493 if ( hasObserver () ) {
494 synchronized ( observer ) { // FIXME : is 'synchronized' useless ?
495 return observer;
496 }
497 } else {
498 return null;
499 }
500 }
501 // DONE
502
503 /**
504 * Removes the current observer of this instance, if any.
505 *
506 * In order to keep the class thread safe (and because I
507 * don't see any reason to have more than one observer),
508 * only one <CODE>FTPClientObserver</CODE> is allowed per
509 * <CODE>FTPClient</CODE>
510 *
511 * @see FTPClient#setObserver(FTPClientObserver)
512 * @see FTPClient#hasObserver()
513 * @see FTPClient#getObserver()
514 * @since v1.0
515 */
516 public void removeObserver ( ) {
517 if ( hasObserver () ) {
518 synchronized ( observer ) {
519 observer.isObserving (false);
520 observer = null;
521 }
522 }
523 }
524 // DONE
525
526
527
528
529 /* FIXME :
530 should we have one method for each method in FTPClientObserver,
531 or
532 one 'blub' function that sorts the different actions that could arise ?
533 */
534
535
536
537
538 /**
539 * Broadcasts the reply received from the server to the
540 * current observer, if any.
541 *
542 * @param reply reply to command received from server
543 * @since v1.0
544 */
545 protected void broadcastReply ( FTPReply reply ) {
546 if ( hasObserver () ) {
547 synchronized ( observer ) {
548 observer.replyReceived (reply);
549 }
550 }
551 }
552 // DONE TESTED
553
554 /**
555 * Broadcasts the command sent to the server to the
556 * current observer, if any.
557 *
558 * @param command string sent to server
559 * @since v1.0
560 */
561 protected void broadcastCommand ( String command ) {
562 if ( hasObserver () ) {
563 synchronized ( observer ) {
564 observer.commandSent (command);
565 }
566 }
567 }
568 // DONE TESTED
569
570 /**
571 * Broadcasts the amount of data received from the
572 * server to the observer, if any.
573 *
574 * @see FTPClient#dataSent(int)
575 * @param bytes amount of data received from server
576 * @since v1.0
577 */
578 protected void dataReceived ( int bytes ) {
579 if ( hasObserver () ) {
580 synchronized ( observer ) {
581 observer.dataReceived (bytes);
582 }
583 }
584 }
585 // DONE
586
587 /**
588 * Broadcasts the amount of data received from the
589 * server to the observer, if any.
590 *
591 * @see FTPClient#dataReceived(int)
592 * @param bytes amount of data sent to server
593 * @since v1.0
594 */
595 protected void dataSent ( int bytes ) {
596 if ( hasObserver () ) {
597 synchronized ( observer ) {
598 observer.dataSent (bytes);
599 }
600 }
601 }
602 // DONE
603
604
605
606
607
608
609
610
611
612
613
614 // ----- IMPLEMENTATION ----
615 /**
616 * Writes the command to the control stream and nofifies
617 * the observer (if it exists).
618 *
619 * @param command FTP command to execute
620 * @exception IOException something goes wrong with
621 * the sockets, streams, ...
622 * @since v1.0
623 */
624 protected synchronized void sendFTPCommand ( String command ) throws IOException {
625 // IMPL : test if connection is alive ?
626 // write command to it
627 writeLineToControlConnection (command);
628 broadcastCommand (command); // notify observer
629 }
630 // DONE TESTED
631
632 /**
633 * Reads replies sent by FTP server on the control stream and
634 * notifies the observer (if it exists).
635 *
636 * @return <CODE>FTPReply</CODE> representation of server's reply.
637 * @exception IOException something goes wrong with
638 * the sockets, streams, ...
639 * @since v1.0
640 */
641 protected synchronized FTPReply readFTPReply ( ) throws IOException {
642 // IMPL : test if connection is alive ?
643 // read one line from stream
644 String line = readLineFromControlConnection ();
645
646 if ( line == null ) {
647 throw new IOException ("Control connection was unexpectidly closed by FTP server."); // FIXME: internationalize !
648 }
649
650 FTPReply reply = new FTPReply (line, locale);
651 broadcastReply (reply); // notify observer
652 return reply;
653 }
654 // DONE TESTED
655
656 /**
657 * Writes a line to the control connection. Usual methods
658 * won't call this method directly, but through
659 * <CODE>sendFTPCommand(String)</CODE>.
660 *
661 * @see org.finj.FTPClient#sendFTPCommand(String)
662 * @return <CODE>FTPReply</CODE> representation of server's reply.
663 * @exception IOException something goes wrong with
664 * the sockets, streams, ...
665 * @since v1.0
666 */
667 protected synchronized void writeLineToControlConnection ( String line ) throws IOException {
668 // IMPL : test if connection is alive ?
669 ctrlOut.println (line);
670 }
671 // DONE TESTED
672
673 /**
674 * Reads a line from the control connection and returns it
675 * without any change. Usual methods won't call this method
676 * directly, but through <CODE>readFTPReply</CODE>.
677 *
678 * @see FTPClient#readFTPReply()
679 * @return <CODE>FTPReply</CODE> representation of server's reply.
680 * @exception IOException something goes wrong with
681 * the sockets, streams, ...
682 * @since v1.0
683 */
684 protected synchronized String readLineFromControlConnection ( ) throws IOException {
685 // IMPL : test if connection is alive ?
686 return ctrlIn.readLine ();
687 }
688 // DONE TESTED
689
690
691
692
693
694
695
696
697 // ----- CONNECTION -----
698
699 /**
700 * Connects to the <CODE>server</CODE> through the
701 * <CODE>DEFAULT_FTP_PORT</CODE>.
702 *
703 * @see FTPClient#open(String,int)
704 * @param server DNS name or IP number of the FTP server to connect to.
705 * @exception IOException something goes wrong with
706 * the sockets, streams, ...
707 * @exception FTPException FTP server is not available or
708 * refuses connections.
709 * @exception UnknownHostException
710 * host doesn't exist.
711 * @since v1.0
712 */
713 public void open ( String server ) throws IOException, FTPException, UnknownHostException {
714 open (server, DEFAULT_FTP_PORT);
715 }
716 // DONE TESTED
717
718 /**
719 * Connects to the <CODE>server</CODE> through the
720 * provided <CODE>port</CODE>.
721 *
722 * @see FTPClient#open(String)
723 * @param server DNS name or IP number of the FTP server to connect to.
724 * @param port TCP port number to use for the control connection.
725 * @exception IOException something goes wrong with
726 * the sockets, streams, ...
727 * @exception FTPException FTP server is not available or
728 * refuses connections.
729 * @exception UnknownHostException
730 * host doesn't exist.
731 * @since v1.0
732 */
733 public void open ( String server,
734 int port ) throws IOException, FTPException, UnknownHostException {
735 if ( isConnected () ) {
736 close ();
737 }
738 // get information on local host machine
739 // open control connection and streams
740 Socket socket = new Socket (server, port);
741 this.serverhost = socket.getInetAddress ();
742 this.localhost = InetAddress.getLocalHost ();
743 // DEPRECATED : debugging info System.err.println (">>> IP ADDRESS OF SERVER (" + this.server.getHostName () + ") IS : " + this.server.getHostAddress ());
744 ctrlIn = new BufferedReader (new InputStreamReader (socket.getInputStream ()));
745 ctrlOut = new PrintWriter (new OutputStreamWriter (socket.getOutputStream ()), true); // with autoflushing
746
747 FTPReply reply = readFTPReply ();
748 switch ( reply.getCode () ) {
749 case FTPReply.CONTROL_CONNECTION_OPENED_CODE : { // success - 220
750 // this reply is ok
751 break;
752 }
753 case FTPReply.WILL_BE_READY_IN_MINUTES_CODE : // intermed - 120
754 case FTPReply.SERVICE_NOT_AVAILABLE_CODE : { // failure - 421
755 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
756 }
757 default : {
758 throw new FTPException (this, reply.getCode (), notValidReplyCodeMessage (reply.getCode (), "OPEN"));
759 }
760 }
761
762 control_port = port;
763 isConnected (true);
764 }
765 // DONE TESTED
766
767 /**
768 * Returns <CODE>true</CODE> if a control connection
769 * is currently opened between this client and
770 * a FTP server, <CODE>false</CODE> else.
771 *
772 * @return current status of the control connection.
773 * @since v1.0
774 */
775 public boolean isConnected ( ) {
776 return connected;
777 }
778 // DONE TESTED
779
780 /**
781 * Sets the current status of the control connection
782 * to the value provided as parameter.
783 *
784 * @see FTPClient#isConnected()
785 * @param isIt value to answer to the
786 * <CODE>isConnected ()</CODE>
787 * method calls.
788 * @since v1.0
789 */
790 protected void isConnected ( boolean isIt ) {
791 if ( hasObserver () ) {
792 if ( isIt ) {
793 observer.controlConnectionOpened ();
794 } else {
795 observer.controlConnectionClosed ();
796 }
797 }
798 connected = isIt;
799 }
800 // DONE TESTED
801
802 /**
803 * Log to the current server using the provided login
804 * information. This is the first method to call on
805 * a server just after <CODE>connect</CODE>ing to it.
806 *
807 * @see "RFC959-4:1:1:'USER'"
808 * @see "RFC959-4:1:1:'PASS'"
809 * @param user User name indentifier to use to log in.
810 * @param pass Password to use to log in.
811 * @exception IOException something goes wrong with
812 * the sockets, streams, ...
813 * @exception FTPException FTP server is not available,
814 * refuses connections or login information.
815 * @since v1.0
816 */
817 public void login ( String user,
818 String pass ) throws IOException, FTPException {
819 doUSERCommand (user); // might throw exceptions...f
820 doPASSCommand (pass);
821 setDataType (dataType);
822 }
823 // DONE TESTED
824
825 /**
826 * Utility routine that takes care to send user information to the server
827 * and treat it's answer. Called before going along with password
828 * or account information.
829 *
830 * @param user User name indentifier to use to log in.
831 * @return FTP code received from server.
832 * @exception IOException something goes wrong with
833 * the sockets, streams, ...
834 * @exception FTPException FTP server is not available,
835 * refuses connections or account information.
836 * @since v1.0
837 */
838 private int doUSERCommand ( String user ) throws IOException, FTPException {
839 sendFTPCommand (new StringBuffer ("USER ").append (user).toString ());
840
841 FTPReply reply = readFTPReply ();
842 switch ( reply.getCode () ) {
843 case FTPReply.USER_LOGGED_IN_CODE : // success - 230
844 case FTPReply.USERNAME_OK_NEED_PASSWORD_CODE : // intermed - 331
845 case FTPReply.NEED_ACCOUNT_FOR_LOGIN_CODE : { // intermed - 332
846 // this reply is ok
847 break;
848 }
849 case FTPReply.SERVICE_NOT_AVAILABLE_CODE : // failure - 421
850 case FTPReply.PERMANENT_NEGATIVE_COMPLETION_REPLY_CODE: // failure - 500
851 case FTPReply.SYNTAX_ERROR_IN_ARGUMENTS_CODE : // failure - 501
852 case FTPReply.NOT_LOGGED_IN_CODE : { // failure - 530
853 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
854 }
855 default : {
856 throw new FTPException (this, reply.getCode (), notValidReplyCodeMessage (reply.getCode (), "USER"));
857 }
858 }
859 return reply.getCode ();
860 }
861 // DONE TESTED
862
863 /**
864 * Utility routine that takes care to send password information to the server
865 * and treat it's answer. Called before going along with (optional)
866 * account information.
867 *
868 * @param pass Password to use to log in.
869 * @return FTP code received from server.
870 * @exception IOException something goes wrong with
871 * the sockets, streams, ...
872 * @exception FTPException FTP server is not available,
873 * refuses connections or account information.
874 * @since v1.0
875 */
876 private int doPASSCommand ( String pass ) throws IOException, FTPException {
877 sendFTPCommand (new StringBuffer ("PASS ").append (pass).toString ());
878
879 FTPReply reply = readFTPReply ();
880 switch ( reply.getCode () ) {
881 case FTPReply.SUPERFLOUS_COMMAND_CODE : // success - 202
882 case FTPReply.USER_LOGGED_IN_CODE : // success - 230
883 case FTPReply.NEED_ACCOUNT_FOR_LOGIN_CODE : { // intermed - 332
884 // this reply is ok
885 break;
886 }
887 case FTPReply.SERVICE_NOT_AVAILABLE_CODE : // failure - 421
888 case FTPReply.PERMANENT_NEGATIVE_COMPLETION_REPLY_CODE : // failure - 500
889 case FTPReply.SYNTAX_ERROR_IN_ARGUMENTS_CODE : // failure - 501
890 case FTPReply.COMMAND_NOT_IMPLEMENTED_CODE : // failure - 502
891 case FTPReply.BAD_COMMAND_SEQUENCE_CODE : // failure - 503
892 case FTPReply.NOT_LOGGED_IN_CODE : { // failure - 530
893 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
894 }
895 default : {
896 throw new FTPException (this, reply.getCode (), notValidReplyCodeMessage (reply.getCode (), "PASS"));
897 }
898 }
899 return reply.getCode ();
900 }
901 // DONE TESTED
902
903 /**
904 * The account data is used to indentify user's account,
905 * but is not necessarily related to the username used to
906 * log in, as some sites may require an account for login
907 * and others only for specific access, such as storing
908 * files. In the latter, the command may arrive at any time.
909 *
910 * @see "RFC959-4:1:1:'ACCT'"
911 * @param value Account data used to identify user.
912 * @exception IOException something goes wrong with
913 * the sockets, streams, ...
914 * @exception FTPException FTP server is not available,
915 * refuses connections or account information.
916 * @since v1.0
917 */
918 public void setAccount ( String value ) throws IOException, FTPException {
919 sendFTPCommand (new StringBuffer ("ACCT ").append (value).toString ());
920
921 FTPReply reply = readFTPReply ();
922 switch ( reply.getCode () ) {
923 case FTPReply.SUPERFLOUS_COMMAND_CODE : // success - 202
924 case FTPReply.USER_LOGGED_IN_CODE : { // success - 230
925 // this reply is ok
926 break;
927 }
928 case FTPReply.SERVICE_NOT_AVAILABLE_CODE : // failure - 421
929 case FTPReply.PERMANENT_NEGATIVE_COMPLETION_REPLY_CODE : // failure - 500
930 case FTPReply.SYNTAX_ERROR_IN_ARGUMENTS_CODE : // failure - 501
931 case FTPReply.BAD_COMMAND_SEQUENCE_CODE : // failure - 503
932 case FTPReply.NOT_LOGGED_IN_CODE : { // failure - 530
933 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
934 }
935 default : {
936 throw new FTPException (this, reply.getCode (), notValidReplyCodeMessage (reply.getCode (), "ACCT"));
937 }
938 }
939 }
940 // DONE
941
942 /**
943 * This method terminates a user, flushing all I/O and account
944 * information, except to allow any transfer in progress to be
945 * completed. All parameters are reset to the default settings
946 * and the control connection is left open, leaving the control
947 * connection in the identical state which a user finds himself
948 * immediately after the control connection is opened using one
949 * of the <CODE>open</CODE> methods. A <CODE>login</CODE> call
950 * may be expected to follow.
951 *
952 * If no <CODE>login</CODE> call is supposed to be taken
953 * after this method, then <CODE>close</CODE> may be a better
954 * guess.
955 *
956 * @see FTPClient#close()
957 * @see "RFC959-4:1:1:'REIN'"
958 * @exception IOException something goes wrong with
959 * the sockets, streams, ...
960 * @exception FTPException FTP server is not available,
961 * refuses connections or account information.
962 * @since v1.0
963 */
964 public void logout ( ) throws IOException, FTPException {
965 sendFTPCommand ("REIN");
966
967 FTPReply reply = readFTPReply ();
968 switch ( reply.getCode () ) {
969 case FTPReply.CONTROL_CONNECTION_OPENED_CODE : { // success - 220
970 // this reply is ok
971 break;
972 }
973 case FTPReply.WILL_BE_READY_IN_MINUTES_CODE : // intermed - 120
974 case FTPReply.SERVICE_NOT_AVAILABLE_CODE : // failure - 421
975 case FTPReply.PERMANENT_NEGATIVE_COMPLETION_REPLY_CODE : // failure - 500
976 case FTPReply.COMMAND_NOT_IMPLEMENTED_CODE : { // failure - 502
977 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
978 }
979 default : {
980 throw new FTPException (this, reply.getCode (), notValidReplyCodeMessage (reply.getCode (), "REIN"));
981 }
982 }
983 }
984 // DONE TESTED
985
986 /**
987 * Defines the HOST-PORT specification for the data port
988 * to be used in data connection. There are defaults for
989 * both the user and server data ports, and under normal
990 * circumstances this command and its reply are not needed.
991 * IF this command is used, the argument is the concatenation
992 * of a 32-bit internet host address and a 16-bit TCP port
993 * address.
994 *
995 * @see FTPClient#getDataPort()
996 * @see FTPClient#setDataPort(int,short)
997 * @see FTPClient#setDataPort(byte,byte,byte,byte,byte,byte)
998 * @see "RFC959-4:1:2:'PORT'"
999 * @param short 16-bits TCP port number to use for the data connection.
1000 * @exception IOException something goes wrong with
1001 * the sockets, streams, ...
1002 * @exception FTPException FTP server is not available or
1003 * refuses connections.
1004 * @since v1.0
1005 */
1006 public void setDataPort ( short port ) throws IOException, FTPException {
1007 // FIXME : ERROR - use local IP address, not server's one !!
1008 byte[] h = localhost.getAddress (); // IP address not provided : consider using localhost one's
1009 // DEPRECATED byte[] h = serverhost.getAddress (); // IP address not provided : consider using FTP server's one
1010 byte[] p = toByteArray (port);
1011 setDataPort (h[0], h[1], h[2], h[3], p[0], p[1]);
1012 }
1013 // DONE
1014
1015 /**
1016 * Defines the HOST-PORT specification for the data port
1017 * to be used in data connection. There are defaults for
1018 * both the user and server data ports, and under normal
1019 * circumstances this command and its reply are not needed.
1020 * IF this command is used, the argument is the concatenation
1021 * of a 32-bit internet host address and a 16-bit TCP port
1022 * address.
1023 *
1024 * @see FTPClient#getDataPort()
1025 * @see FTPClient#setDataPort(short)
1026 * @see FTPClient#setDataPort(byte,byte,byte,byte,byte,byte)
1027 * @see "RFC959-4:1:2:'PORT'"
1028 * @param host 32-bits IP host address to use for the data connection.
1029 * @param port 16-bits TCP port number to use for the data connection.
1030 * @exception IOException something goes wrong with
1031 * the sockets, streams, ...
1032 * @exception FTPException FTP server is not available or
1033 * refuses connections.
1034 * @since v1.0
1035 */
1036 public void setDataPort ( int host,
1037 short port ) throws IOException, FTPException {
1038 byte[] h = toByteArray (host);
1039 byte[] p = toByteArray (port);
1040 setDataPort (h[0], h[1], h[2], h[3], p[0], p[1]);
1041 }
1042 // DONE
1043
1044 /**
1045 * Defines the HOST-PORT specification for the data port
1046 * to be used in data connection. There are defaults for
1047 * both the user and server data ports, and under normal
1048 * circumstances this command and its reply are not needed.
1049 * IF this command is used, the argument is the concatenation
1050 * of a 32-bit internet host address and a 16-bit TCP port
1051 * address.
1052 *
1053 * @see FTPClient#getDataPort()
1054 * @see FTPClient#setDataPort(short)
1055 * @see FTPClient#setDataPort(int,short)
1056 * @see "RFC959-4:1:2:'PORT'"
1057 * @param host_1 bits 1 to 8 of IP host address to use for the data connection.
1058 * @param host_2 bits 9 to 16 of IP host address to use for the data connection.
1059 * @param host_3 bits 17 to 24 of IP host address to use for the data connection.
1060 * @param host_4 bits 25 to 32 of IP host address to use for the data connection.
1061 * @param port_1 bits 1 to 8 of TCP port number to use for the data connection.
1062 * @param port_2 bits 9 to 16 of TCP port number to use for the data connection.
1063 * @exception IOException something goes wrong with
1064 * the sockets, streams, ...
1065 * @exception FTPException FTP server is not available or
1066 * refuses connections.
1067 * @since v1.0
1068 */
1069 public void setDataPort ( byte host_1,
1070 byte host_2,
1071 byte host_3,
1072 byte host_4,
1073 byte port_1,
1074 byte port_2 ) throws IOException, FTPException {
1075 sendFTPCommand (new StringBuffer ("PORT ")
1076 .append (toUnsignedShort (host_1))
1077 .append (",")
1078 .append (toUnsignedShort (host_2))
1079 .append (",")
1080 .append (toUnsignedShort (host_3))
1081 .append (",")
1082 .append (toUnsignedShort (host_4))
1083 .append (",")
1084 .append (toUnsignedShort (port_1))
1085 .append (",")
1086 .append (toUnsignedShort (port_2))
1087 .toString ());
1088
1089 FTPReply reply = readFTPReply ();
1090 switch ( reply.getCode () ) {
1091 case FTPReply.POSITIVE_COMPLETION_REPLY_CODE : { // success - 200
1092 // this reply is ok
1093 break;
1094 }
1095 case FTPReply.SERVICE_NOT_AVAILABLE_CODE : // failure - 421
1096 case FTPReply.PERMANENT_NEGATIVE_COMPLETION_REPLY_CODE : // failure - 500
1097 case FTPReply.SYNTAX_ERROR_IN_ARGUMENTS_CODE : // failure - 501
1098 case FTPReply.NOT_LOGGED_IN_CODE : { // failure - 530
1099 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
1100 }
1101 default : {
1102 throw new FTPException (this, reply.getCode (), notValidReplyCodeMessage (reply.getCode (), "PORT"));
1103 }
1104 }
1105
1106 dataHost = new byte[] {host_1, host_2, host_3, host_4}; // FIXME : isn't that useless ??
1107 dataPort = new byte[] {port_1, port_2}; // FIXME : isn't that useless ??
1108 }
1109 // DONE
1110
1111 /**
1112 * Returns the HOST-PORT used for the data connection.
1113 *
1114 * @see FTPClient#setDataPort(short)
1115 * @see FTPClient#setDataPort(int,short)
1116 * @see FTPClient#setDataPort(byte,byte,byte,byte,byte,byte)
1117 * @return current data port value.
1118 * @since v1.0
1119 */
1120 public byte[] getDataPort ( ) {
1121 return dataPort;
1122 }
1123 // DONE
1124
1125 /**
1126 * Returns the current data type manipulated, that is one of
1127 * <CODE>FTPClient.ASCII_DATA_TYPE</CODE> (default value),
1128 * <CODE>FTPClient.EBCDIC_DATA_TYPE</CODE>,
1129 * <CODE>FTPClient.IMAGE_DATA_TYPE</CODE>,
1130 * <CODE>FTPClient.LOCAL_DATA_TYPE</CODE>.
1131 *
1132 * @see FTPClient#setDataType(int)
1133 * @see FTPClient#setDataType(int,int)
1134 * @return current data type manipulated.
1135 * @since v1.0
1136 */
1137 public int getDataType ( ) {
1138 return dataType;
1139 }
1140 // DONE
1141
1142 /**
1143 * Data representations are handled in FTP by a user specifying
1144 * a representation type. This type may implicitly (as ASCII or
1145 * EBCDIC) or explicitly (as in Local byte) define a byte size
1146 * for interpretation which is referred to as the "logical byte size".
1147 * Note that this has nothing to do with the byte size used for
1148 * transmission over the data connection, called the "transfer
1149 * byte size", and the two should not be confused.
1150 *
1151 * @see FTPClient#setDataType(int,int)
1152 * @see FTPClient#getDataType()
1153 * @see "RFC959-3:1:1:Data types"
1154 * @see "RFC959-4:1:2:'TYPE'"
1155 * @param type one of
1156 * <CODE>FTPClient.ASCII_DATA_TYPE</CODE> (default value),
1157 * <CODE>FTPClient.EBCDIC_DATA_TYPE</CODE>,
1158 * <CODE>FTPClient.IMAGE_DATA_TYPE</CODE>,
1159 * <CODE>FTPClient.LOCAL_DATA_TYPE</CODE>.
1160 * @exception IOException something goes wrong with
1161 * the sockets, streams, ...
1162 * @exception FTPException FTP server is not available or
1163 * refuses connections.
1164 * @exception IllegalArgumentException
1165 * <CODE>type</CODE> is not one of those allowed, or
1166 * a parameter is missing.
1167 * @since v1.0
1168 */
1169 public void setDataType ( int type ) throws IOException, FTPException, IllegalArgumentException {
1170 if ( type != LOCAL_DATA_TYPE ) {
1171 setDataType (type, 8); // '8' is dummy : it won't even be really sent.
1172 } else {
1173 throw new IllegalArgumentException ("LOCAL_DATA_TYPE requires a second parameter. Use setDataType(int,int) instead."); // FIXME : internationalize !
1174 }
1175 }
1176 // DONE
1177
1178 /**
1179 * Works just as <CODE>setDataType (int)</CODE>, except that if the type
1180 * is <CODE>FTPClient.LOCAL_DATA_TYPE</CODE>, then the second parameter
1181 * (which is useless for the other types) must be the "logical byte size".
1182 *
1183 * @see FTPClient#setDataType(int)
1184 * @see FTPClient#getDataType()
1185 * @see "RFC959-3:1:1:Data types"
1186 * @see "RFC959-4:1:2:'TYPE'"
1187 * @param type usually <CODE>FTPClient.LOCAL_DATA_TYPE</CODE>, or
1188 * the second parameter will be dummy.
1189 * @param bytes useless for all types except <CODE>LOCAL_DATA_TYPE</CODE>
1190 * when it sets the "logical byte size".
1191 * @exception IOException something goes wrong with
1192 * the sockets, streams, ...
1193 * @exception FTPException FTP server is not available or
1194 * refuses connections.
1195 * @exception IllegalArgumentException
1196 * <CODE>type</CODE> is not one of those allowed.
1197 * @since v1.0
1198 */
1199 public void setDataType ( int type,
1200 int bytes ) throws IOException, FTPException, IllegalArgumentException {
1201 StringBuffer command = new StringBuffer ("TYPE ");
1202 switch ( type ) {
1203 case IMAGE_DATA_TYPE : {
1204 command.append ("I");
1205 break;
1206 }
1207 case ASCII_DATA_TYPE : {
1208 command.append ("A");
1209 break;
1210 }
1211 case EBCDIC_DATA_TYPE : {
1212 command.append ("E");
1213 break;
1214 }
1215 case LOCAL_DATA_TYPE : {
1216 command.append ("L ").append (bytes);
1217 break;
1218 }
1219 default : {
1220 throw new IllegalArgumentException ("Type passed as parameter must be one of ASCII_DATA_TYPE, EBCDIC_DATA_TYPE, IMAGE_DATA_TYPE or LOCAL_DATA_TYPE."); // FIXME : internationalize !
1221 }
1222 }
1223
1224 sendFTPCommand (command.toString ());
1225
1226 FTPReply reply = readFTPReply ();
1227 switch ( reply.getCode () ) {
1228 case FTPReply.POSITIVE_COMPLETION_REPLY_CODE : { // success - 200
1229 // this reply is ok
1230 break;
1231 }
1232 case FTPReply.SERVICE_NOT_AVAILABLE_CODE : // failure - 421
1233 case FTPReply.PERMANENT_NEGATIVE_COMPLETION_REPLY_CODE : // failure - 500
1234 case FTPReply.SYNTAX_ERROR_IN_ARGUMENTS_CODE : // failure - 501
1235 case FTPReply.COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER_CODE : // failure - 504
1236 case FTPReply.NOT_LOGGED_IN_CODE : { // failure - 530
1237 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
1238 }
1239 default : {
1240 throw new FTPException (this, reply.getCode (), notValidReplyCodeMessage (reply.getCode (), "TYPE"));
1241 }
1242 }
1243
1244 dataType = type;
1245 dataTypeLength = bytes;
1246 }
1247 // DONE
1248
1249 /**
1250 * Returns the current data structure manipulated, that is one of
1251 * <CODE>FTPClient.FILE_DATA_STRUCTURE</CODE> (default value),
1252 * <CODE>FTPClient.RECORD_DATA_STRUCTURE</CODE>,
1253 * <CODE>FTPClient.PAGE_DATA_STRUCTURE</CODE>.
1254 *
1255 * @see FTPClient#setDataStructure(int)
1256 * @return current data structure manipulated.
1257 * @since v1.0
1258 */
1259 public int getDataStructure ( ) {
1260 return dataStructure;
1261 }
1262 // DONE
1263
1264 /**
1265 * In addition to different representation types, FTP allows
1266 * the structure of a file to be specified. Both <CODE>FILE</CODE>
1267 * and <CODE>RECORD</CODE> structures are accepted for "text" files.
1268 *
1269 * @see FTPClient#getDataStructure()
1270 * @see "RFC959-3:1:2:Data structures"
1271 * @see "RFC959-4:1:2:'STRU'"
1272 * @param type one of
1273 * <CODE>FTPClient.FILE_DATA_STRUCTURE</CODE> (default value),
1274 * <CODE>FTPClient.RECORD_DATA_STRUCTURE</CODE>,
1275 * <CODE>FTPClient.PAGE_DATA_STRUCTURE</CODE>.
1276 * @exception IOException something goes wrong with
1277 * the sockets, streams, ...
1278 * @exception FTPException FTP server is not available or
1279 * refuses connections.
1280 * @exception IllegalArgumentException
1281 * <CODE>structure</CODE> is not one of those allowed.
1282 * @since v1.0
1283 */
1284 public void setDataStructure ( int structure ) throws IOException, FTPException, IllegalArgumentException {
1285 StringBuffer command = new StringBuffer ("STRU ");
1286 switch ( structure ) {
1287 case FILE_DATA_STRUCTURE : {
1288 command.append ("file");
1289 break;
1290 }
1291 case RECORD_DATA_STRUCTURE : {
1292 command.append ("record");
1293 break;
1294 }
1295 case PAGE_DATA_STRUCTURE : {
1296 command.append ("page");
1297 break;
1298 }
1299 default : {
1300 throw new IllegalArgumentException ("Structure passed as parameter must be one of FILE_DATA_STRUCTURE, RECORD_DATA_STRUCTURE, or PAGE_DATA_STRUCTURE."); // FIXME : internationalize !
1301 }
1302 }
1303 sendFTPCommand (command.toString ());
1304
1305 FTPReply reply = readFTPReply ();
1306 switch ( reply.getCode () ) {
1307 case FTPReply.POSITIVE_COMPLETION_REPLY_CODE : { // success - 200
1308 // this reply is ok
1309 break;
1310 }
1311 case FTPReply.SERVICE_NOT_AVAILABLE_CODE : // failure - 421
1312 case FTPReply.PERMANENT_NEGATIVE_COMPLETION_REPLY_CODE : // failure - 500
1313 case FTPReply.SYNTAX_ERROR_IN_ARGUMENTS_CODE : // failure - 501
1314 case FTPReply.COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER_CODE : // failure - 504
1315 case FTPReply.NOT_LOGGED_IN_CODE : { // failure - 530
1316 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
1317 }
1318 default : {
1319 throw new FTPException (this, reply.getCode (), notValidReplyCodeMessage (reply.getCode (), "STRU"));
1320 }
1321 }
1322
1323 dataStructure = structure;
1324 }
1325 // DONE
1326
1327 /**
1328 * Returns the data transmission mode currently used, that is one of
1329 * <CODE>FTPClient.STREAM_DATA_TRANSMISSION_MODE</CODE> (default value),
1330 * <CODE>FTPClient.BLOCK_DATA_TRANSMISSION_MODE</CODE>,
1331 * <CODE>FTPClient.COMPRESSED_DATA_TRANSMISSION_MODE</CODE>.
1332 *
1333 * @see FTPClient#setDataTransferMode(int)
1334 * @return current data transmission mode used.
1335 * @since v1.0
1336 */
1337 public int getDataTransferMode ( ) {
1338 return dataMode;
1339 }
1340 // DONE
1341
1342 /**
1343 * There are three transmission mode available,
1344 * one which formats the data and allows for restart procedures;
1345 * one which also compresses the data for efficient transfer;
1346 * and one which passes the data with little or no processing.
1347 * in this last case the mode interacts with the structure
1348 * attribute to determine the type of processing. In the
1349 * compressed mode, the representation type determines the
1350 * filler byte.
1351 *
1352 * @see FTPClient#getDataTransferMode()
1353 * @see "RFC959-3:4:Transmission modes"
1354 * @see "RFC959-4:1:2:'MODE'"
1355 * @param type one of
1356 * <CODE>FTPClient.STREAM_DATA_TRANSMISSION_MODE</CODE> (default value),
1357 * <CODE>FTPClient.BLOCK_DATA_TRANSMISSION_MODE</CODE>,
1358 * <CODE>FTPClient.COMPRESSED_DATA_TRANSMISSION_MODE</CODE>.
1359 * @exception IOException something goes wrong with
1360 * the sockets, streams, ...
1361 * @exception FTPException FTP server is not available or
1362 * refuses connections.
1363 * @since v1.0
1364 */
1365 public void setDataTransferMode ( int mode ) throws IOException, FTPException, IllegalArgumentException {
1366 StringBuffer command = new StringBuffer ("MODE ");
1367 switch ( mode ) {
1368 case STREAM_DATA_TRANSMISSION_MODE : {
1369 command.append ("stream");
1370 break;
1371 }
1372 case BLOCK_DATA_TRANSMISSION_MODE : {
1373 command.append ("block");
1374 break;
1375 }
1376 case COMPRESSED_DATA_TRANSMISSION_MODE : {
1377 command.append ("compressed");
1378 break;
1379 }
1380 default : {
1381 throw new IllegalArgumentException ("Mode passed as parameter must be one of STREAM_DATA_TRANSMISSION_MODE, BLOCK_DATA_TRANSMISSION_MODE, or COMPRESSED_DATA_TRANSMISSION_MODE"); // FIXME : internationalize !
1382 }
1383 }
1384 sendFTPCommand (command.toString ());
1385
1386 FTPReply reply = readFTPReply ();
1387 switch ( reply.getCode () ) {
1388 case FTPReply.POSITIVE_COMPLETION_REPLY_CODE : { // success - 200
1389 // this reply is ok
1390 break;
1391 }
1392 case FTPReply.SERVICE_NOT_AVAILABLE_CODE : // failure - 421
1393 case FTPReply.PERMANENT_NEGATIVE_COMPLETION_REPLY_CODE : // failure - 500
1394 case FTPReply.SYNTAX_ERROR_IN_ARGUMENTS_CODE : // failure - 501
1395 case FTPReply.COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER_CODE : // failure - 504
1396 case FTPReply.NOT_LOGGED_IN_CODE : { // failure - 530
1397 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
1398 }
1399 default : {
1400 throw new FTPException (this, reply.getCode (), notValidReplyCodeMessage (reply.getCode (), "MODE"));
1401 }
1402 }
1403
1404 dataMode = mode;
1405 }
1406 // DONE
1407
1408 /**
1409 * This command requests the server-DTP to "listen" on a data
1410 * port (which is not its default data port) and to wait for a
1411 * connection rather that initiate one upon receipt of a transfer
1412 * command.
1413 *
1414 * @see "RFC959-4:1:2:'PASV'"
1415 * @return host and port address server will be listening to.
1416 * @exception IOException something goes wrong with
1417 * the sockets, streams, ...
1418 * @exception FTPException FTP server is not available or
1419 * refuses connections.
1420 * @since v1.0
1421 */
1422 public byte[] setPassive ( ) throws IOException, FTPException {
1423 sendFTPCommand ("PASV");
1424
1425 FTPReply reply = readFTPReply ();
1426 switch ( reply.getCode () ) {
1427 case FTPReply.ENTERING_PASSIVE_MODE_CODE : { // success - 227
1428 // this reply is ok
1429 break;
1430 }
1431 case FTPReply.SERVICE_NOT_AVAILABLE_CODE : // failure - 421
1432 case FTPReply.PERMANENT_NEGATIVE_COMPLETION_REPLY_CODE : // failure - 500
1433 case FTPReply.SYNTAX_ERROR_IN_ARGUMENTS_CODE : // failure - 501
1434 case FTPReply.COMMAND_NOT_IMPLEMENTED_CODE : // failure - 502
1435 case FTPReply.NOT_LOGGED_IN_CODE : { // failure - 530
1436 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
1437 }
1438 default : {
1439 throw new FTPException (this, reply.getCode (), notValidReplyCodeMessage (reply.getCode (), "PASV"));
1440 }
1441 }
1442
1443 // IMPL : parse answer
1444 // IMPL : return host+port address
1445 return new byte[0]; // FIXME : remove me
1446 }
1447 // TOBEDONE
1448
1449 /**
1450 * This method terminates a user and if file transfer is not in
1451 * progress, the server closes the control connection. If file
1452 * transfer is in progress, the connection will remain open
1453 * for result response and the server will then close it.
1454 *
1455 * If the user-process is transferring files for several
1456 * users, but does not wish to close and then reopen connections
1457 * for each, the <CODE>logout</CODE> followed by the
1458 * <CODE>login</CODE> methods should be called instead.
1459 *
1460 * @see FTPClient#logout()
1461 * @see "RFC959-4:1:1:'QUIT'"
1462 * @exception IOException something goes wrong with
1463 * the sockets, streams, ...
1464 * @exception FTPException FTP server is not available or
1465 * refuses connections.
1466 * @since v1.0
1467 */
1468 public void close ( ) throws IOException, FTPException {
1469 sendFTPCommand ("QUIT");
1470
1471 FTPReply reply = readFTPReply ();
1472 switch ( reply.getCode () ) {
1473 case FTPReply.CONTROL_CONNECTION_CLOSED_CODE : { // success - 221
1474 // this reply is ok
1475 break;
1476 }
1477 case FTPReply.PERMANENT_NEGATIVE_COMPLETION_REPLY_CODE : { // failure - 500
1478 throw new FTPException (this, reply.getCode (), reply.getOriginalMessage ());
1479 }
1480 default : {
1481 throw