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

Quick Search    Search Deep

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