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

Quick Search    Search Deep

Source code: com/yaftp/ftp/FtpClientSession.java


1    /**
2    *
3    * CopyRights Jean-Yves MENGANT 1999,2000,2001,2002
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18   */
19  
20  package com.yaftp.ftp ;
21  
22  /**
23  
24    Build a basic FTP prococol class using Multiple java threads
25  
26    @Author Jean-Yves MENGANT
27    @version : 0.0.1
28  
29  */
30  
31  import java.net.* ;
32  import java.io.*  ;
33  import java.util.* ;
34  import java.lang.Thread ;
35  
36  // Local project utils imports
37  import com.yaftp.utils.* ;
38  
39  
40  /**
41  
42    FtpClientSession is the main Ftp access class
43  
44  */
45  
46  public class FtpClientSession
47  implements FtpConnection
48  {
49    private static final String   _EMPTY_ = "" ;
50    private static final int      FTP_DEFAULT_COMMAND_PORT = 21 ;
51    private static final int      FTP_DEFAULT_DATA_PORT    = 1150 ;
52    private static final short    MAX_UNSIGNED_BYTE        = 256  ;
53  
54    // Some stable FTP standard return code categories defined as constant
55  
56    private static final int FTP_POSITIVE_PRELIMINARY_REPLY    = 1 ;
57    private static final int FTP_POSITIVE_COMPLETION_REPLY     = 2 ;
58    private static final int FTP_POSITIVE_INTERMEDIATE_REPLY   = 3 ;
59    private static final int FTP_TRANSIENT_NEGATIVE_COMPLETION = 4 ;
60    private static final int FTP_PERMANENT_NEGATIVE_COMPLETION = 5 ;
61  
62    private static final int FTP_COMMAND_OK             = 200 ;
63    private static final int FTP_SYSTEM_TYPE            = 215 ;
64    private static final int FTP_SUCCESSFULL_CONNECTION = 220 ;
65    private static final int FTP_FILE_NOT_AVAILABLE     = 550 ;
66    private static final int FTP_PASV_OPEN              = 227 ;
67    private static final int FTP_PASV_CLOSE             = 226 ;
68    /** this code is used by MVS FTP server */
69    private static final int FTP_PASV_CLOSE_ALTERNATE   = 250 ;
70  
71    private static final String _OPENPAR_ = "(" ;
72    private static final String _CLOSEPAR_ = ")" ;
73    private static final String _COMMA_ = "," ;
74    private static final String _DOT_ = "." ;
75  
76  
77    private int                        _commandPort = FTP_DEFAULT_COMMAND_PORT ;
78    private String                     _ftpSrvName  ;
79    transient private CommandSocket    _cmdSock     ; // Use this socket for command
80    private String                     _currentUser ;
81    private String                     _currentPsw  ;
82  
83    transient  private   FtpTraces _traces = new FtpTraces(this)  ; // optional ftp traces
84  
85    transient private FtpDataNotifier  _dataEvt    ;// DATA is ready
86    transient private Ftp              _parent      ; // the Launcher
87  
88    transient private FtpSessionOs     _serverOS    ; // What is FTP Server Os
89    transient private String _lastCommandMessage ;
90    transient private String _directoryMessage ;
91  
92    public String get_lastCommandMessage()
93    { return _lastCommandMessage ; }
94  
95    public String getDirectoryMessage()
96    { return _directoryMessage ; }
97  
98  
99    /**
100 
101     CommandSocket INNER CLASS is used to deal with FTP COMMAND port
102 
103   */
104 
105   // Use socket below to send commands to FTP server
106   class CommandSocket extends Socket {
107 
108     private BufferedWriter     _cmdStream   ; // Use it to build FTP commands
109     private BufferedReader     _answStream  ; // Use it to collect command status
110     private int                _lastReturn  ; // value of last command return code
111     private int                _lastReturnType ; // Last return error category
112     private String             _lastMessage ; // Last returned Message
113     private DataSocket         _dataSock    ; // Use this for Ftp Data
114     private FtpClientListener  _rListener   ; // the one listening to data
115     private Socket             _pasvSocket  ; // client socket used to RETR files in PASV mode
116 
117     // following data is stored in order to be able to reconnect when
118     // FTP session times out
119     private String             _loggedUser ;
120     private String             _ftpPaswd   ;
121 
122     // Collect Ftp server last command Status
123     private void getStatus()
124     throws ClientFtpError
125     {
126       String header      = _EMPTY_ ;
127       String headerFirst = _EMPTY_ ;
128       try {
129         _lastMessage = _answStream.readLine() ;
130 
131         // this may happen if ftp connection has broken
132         if ( _lastMessage == null )
133         return ;
134 
135         if ( _lastMessage.length() >= 3 )
136         {
137           header = _lastMessage.substring(0,3) ;
138           headerFirst = _lastMessage.substring(0,1) ;
139 
140           StringBuffer collector = new StringBuffer( _lastMessage ) ;
141           while ( _lastMessage.charAt(3) == '-' )
142           {
143             _lastMessage = _answStream.readLine() ;
144             _traces.header(_lastMessage) ;
145             collector.append( ";" + _lastMessage ) ;
146           }
147           _lastMessage = collector.toString() ;
148         }
149 
150       } catch ( IOException e )
151       { throw new ClientFtpError(" Ftp socket Read Status error " +
152                                e.toString() ) ;
153       }
154 
155       try {
156         _lastReturn     = new Integer(header).intValue() ;
157         _lastReturnType = new Integer(headerFirst).intValue() ;
158       } catch ( NumberFormatException e )
159       {
160         // sometimes FTP servers may not comply the RFC about status
161         // starting with 3 digits codes and assume that message is informative
162         // and assume a command OK return code then
163         _lastReturnType = FTP_POSITIVE_COMPLETION_REPLY ;
164         _lastReturn     = FTP_COMMAND_OK                ;
165       }
166 
167       if (( _lastReturnType == FTP_TRANSIENT_NEGATIVE_COMPLETION ) ||
168           ( _lastReturnType == FTP_PERMANENT_NEGATIVE_COMPLETION )
169          )
170       {
171         _traces.error(_lastMessage) ;
172         throw new ClientFtpError( _lastMessage ) ;
173       }
174       else
175         _traces.header(_lastMessage) ;
176 
177       _traces.trace("last error type is : " + _lastReturnType ) ;
178       _lastCommandMessage = _lastMessage ;
179     }
180 
181     // Sending a command to FTP server
182     private void sendCommand( String cmd )
183     throws ClientFtpError
184     {
185       _dataEvt.setDataNotAvailable() ; // Reset read data availability to false
186       if ( _rListener != null )
187         _rListener.set_dataMessage(null)   ; // Reset any data process error
188       _traces.trace(" before executing : "+ cmd) ;
189       try {
190         _cmdStream.write(cmd + "\n") ;
191         _cmdStream.flush()        ;
192       } catch ( IOException e )
193       { throw new ClientFtpError(" Ftp socket Write Command error " +
194                                e.toString() ) ;
195       }
196       getStatus()               ;
197     }
198 
199     // Launch DATAListener thread and give back listening port number
200     private void launchDATAListenerThread()
201     throws ClientFtpError
202     {
203       _dataSock = new DataSocket() ;
204       // Start Data Thread
205       _traces.trace("Starting Thread for :"+_dataSock.toString()) ;
206       _dataSock.start() ;
207 
208     }
209 
210     // build a full valid PORT command string ready to execute
211     private String buildPORTCommand( int dataPort )
212     throws ClientFtpError
213     {
214       // Since client connection may have multiple Internet adresses
215       // (ie : on PPP on ETH on Loopback ... the only way to kow
216       // which IP adress is used by FTP is to query the opened socket
217       StringBuffer hostAdr = new StringBuffer(getLocalAddress().getHostAddress()) ;
218 
219       while ( hostAdr.toString().indexOf('.') != -1 )
220         hostAdr.setCharAt( hostAdr.toString().indexOf('.') , ',' )  ;
221 
222       int hiPort = BYTEFX.HIBYTE((short)dataPort)  ;
223       int loPort = BYTEFX.LOWBYTE((short)dataPort) ;
224 
225       if ( hiPort < 0 )
226         hiPort = MAX_UNSIGNED_BYTE + hiPort ;
227 
228       if ( loPort < 0 )
229         loPort = MAX_UNSIGNED_BYTE + loPort  ;
230 
231       _traces.trace(" Port : " + dataPort + "h :" + hiPort +" l: " + loPort) ;
232 
233       return( "PORT " + hostAdr + "," + String.valueOf(hiPort) + ","
234               +  String.valueOf(loPort)
235             ) ;
236     }
237 
238     // Sync with Data
239     private void cmdWaitForDATA()
240     throws ClientFtpError
241     {
242        _dataEvt.waitForData() ;
243        // check that nothing bad has happened in data socket thread
244        if ( _rListener.get_dataMessage() != null )
245          throw new ClientFtpError( _rListener.get_dataMessage() ) ;
246     }
247 
248     private void pasvReceiveData()
249     throws ClientFtpError
250     {
251       // Activate reader
252       try {
253        _rListener.readData( _pasvSocket.getInputStream() , _dataEvt ) ;
254        _pasvSocket.close() ;
255        _pasvSocket = null  ;
256       } catch( IOException e ) {
257         throw new ClientFtpError( " PASV reader failed IOERR : " +
258                                    e.toString()
259                                  ) ;
260       }
261       // check that nothing bad has happened in data socket thread
262       if ( _rListener.get_dataMessage() != null )
263         throw new ClientFtpError( _rListener.get_dataMessage() ) ;
264     }
265 
266     private void pasvSendData()
267     throws ClientFtpError
268     {
269       // Activate reader
270       try {
271        _rListener.writeData( _pasvSocket.getOutputStream() , _dataEvt ) ;
272        _pasvSocket.close() ;
273        _pasvSocket = null  ;
274       } catch( IOException e ) {
275         throw new ClientFtpError( " PASV writer failed IOERR : " +
276                                    e.toString()
277                                  ) ;
278       }
279       // check that nothing bad has happened in data socket thread
280       if ( _rListener.get_dataMessage() != null )
281         throw new ClientFtpError( _rListener.get_dataMessage() ) ;
282     }
283 
284     // FTP implemented COMMAND list in UPPERCASE follow
285 
286     // set data Callback object
287     public void set_rListener( FtpClientListener callback )
288     {
289       _rListener = callback ;
290       _dataSock.set_callback(callback) ;
291     }
292 
293     // Basic NOOP for testing purposes
294     public void NOOP()
295     throws ClientFtpError
296     {  sendCommand("NOOP") ; }
297 
298     // Basic SITE
299     public String SITE( String value )
300     throws ClientFtpError
301     {
302       sendCommand("SITE "+value) ;
303       return(_lastMessage) ;
304     }
305 
306     // Basic LOGIN to ftp server
307     public void LOGIN( String userid ,
308                        String Passwd ,
309                        FtpSessionOs sessionOs
310                      )
311     throws ClientFtpError
312     {
313       _currentUser = userid ;
314       _currentPsw  = Passwd ;
315 
316       if ( _currentPsw == null )
317         _currentPsw = new String("") ;
318 
319       sendCommand( "USER "+ _currentUser ) ;
320       sendCommand( "PASS " + _currentPsw ) ;
321       SYST() ; // Query system after login some FTP do not support this
322                // command before
323       if ( sessionOs == null ) // not choosed by user try to guess it
324         _serverOS = new FtpSessionOs(_lastMessage) ;
325       else
326         _serverOS = sessionOs ;
327     }
328 
329     // do a basic LIST on server current directory using PORT protocol
330     public void LISTPORT()
331     throws ClientFtpError
332     {
333        _dataSock.setReader() ;
334        sendCommand( buildPORTCommand( _dataSock.getPort() ) ) ;
335        sendCommand("LIST") ;
336        cmdWaitForDATA() ;
337        getStatus() ;
338     }
339 
340     // do a basic LIST on server current directory using PORT protocol
341     public void LISTPASV()
342     throws ClientFtpError
343     {
344        _dataSock.setReader() ;
345        PASV() ;
346        sendCommand("LIST") ;
347        pasvReceiveData() ;
348        PASV() ;
349        getStatus() ;
350     }
351 
352     // send QUIT
353     public void QUIT()
354     throws ClientFtpError
355     {  sendCommand("QUIT") ; }
356 
357     // use SYST to determine host type
358     public void SYST()
359     throws ClientFtpError
360     {
361       sendCommand("SYST") ;
362       // Some FTP server may provide UNEXPECTED VERBOSITY
363       // on this command and are not emitting the expected 215
364       // return status immediately => we should track it
365 
366       while ( _lastReturn != FTP_SYSTEM_TYPE )
367       {
368         if ( _lastReturnType > FTP_POSITIVE_INTERMEDIATE_REPLY ) // give up on severe
369           throw new ClientFtpError( _lastMessage ) ;
370         getStatus() ;
371       }
372     }
373 
374     public void CWDIR( String dirName )
375     throws ClientFtpError
376     {
377       _serverOS.convertDirectory(dirName) ;
378       sendCommand("CWD " + _serverOS.getCurDirectory() ) ;
379       _directoryMessage = _serverOS.checkCurDirectory( _lastMessage ) ;
380     }
381 
382     public void MKDIR( String dirName )
383     throws ClientFtpError
384     {
385       _serverOS.convertDirectory(dirName) ;
386       sendCommand("MKD " + _serverOS.getCurDirectory() ) ;
387     }
388 
389     public void RMDIR( String dirName )
390     throws ClientFtpError
391     {
392       _serverOS.convertDirectory(dirName) ;
393       sendCommand("RMD " + _serverOS.getCurDirectory() ) ;
394     }
395 
396     public void RENAME( String from , String to )
397     throws ClientFtpError
398     {
399       sendCommand("RNFR " + from ) ;
400       sendCommand("RNTO " + to ) ;
401     }
402 
403     // send a DELE command on given file
404     public boolean DELETE( String candidate )
405     throws ClientFtpError
406     {
407       try {
408         sendCommand("DELE " + candidate ) ;
409       } catch ( ClientFtpError e )
410       {
411          // just capture the file not found case
412          if ( _lastReturn == FTP_FILE_NOT_AVAILABLE )
413            return false ;
414          else
415            throw e ;
416       }
417       return true ;
418     }
419 
420     // GET requested file using PORT protocol
421     public void GETPORT ( String fName )
422     throws ClientFtpError
423     {
424       _serverOS.parseFileName(fName)  ;
425       if (
426            ( _serverOS.getCurDirectory() != null )&&
427            ( _serverOS.hasDirChanged() )
428          )
429         sendCommand("CWD " + _serverOS.getCurDirectory() ) ;
430       _dataSock.setReader() ;
431       sendCommand( buildPORTCommand( _dataSock.getPort() ) ) ;
432       sendCommand("RETR " + _serverOS.getCurFile() ) ;
433       cmdWaitForDATA() ;
434       getStatus() ;
435     }
436 
437     // GET requested file using PASV protocol
438     public void GETPASV ( String fName )
439     throws ClientFtpError
440     {
441       _serverOS.parseFileName(fName)  ;
442       if (
443            ( _serverOS.getCurDirectory() != null )&&
444            ( _serverOS.hasDirChanged() )
445          )
446         sendCommand("CWD " + _serverOS.getCurDirectory() ) ;
447       PASV() ;
448       sendCommand("RETR " + _serverOS.getCurFile() ) ;
449       pasvReceiveData() ;
450       PASV() ;
451       getStatus() ;
452     }
453 
454     // PUT requested file in PORT mode
455     public void PUTPORT ( String fName )
456     throws ClientFtpError
457     {
458       _serverOS.parseFileName(fName)  ;
459       if (
460            ( _serverOS.getCurDirectory() != null )&&
461            ( _serverOS.hasDirChanged() )
462          )
463         sendCommand("CWD " + _serverOS.getCurDirectory() ) ;
464       _dataSock.setWriter() ;
465       sendCommand( buildPORTCommand( _dataSock.getPort() ) ) ;
466       sendCommand("STOR " + _serverOS.getCurFile() ) ;
467       cmdWaitForDATA() ;
468       getStatus() ;
469     }
470 
471     // GET requested file using PASV protocol
472     public void PUTPASV ( String fName )
473     throws ClientFtpError
474     {
475       _serverOS.parseFileName(fName)  ;
476       if (
477            ( _serverOS.getCurDirectory() != null )&&
478            ( _serverOS.hasDirChanged() )
479          )
480         sendCommand("CWD " + _serverOS.getCurDirectory() ) ;
481       PASV() ;
482       sendCommand("STOR " + _serverOS.getCurFile() ) ;
483       pasvSendData() ;
484       PASV() ;
485       getStatus() ;
486     }
487 
488 
489     // Just Stop DATA thread
490     // And Quit FTP
491     public void STOP()
492     throws ClientFtpError
493     {
494        QUIT() ;
495        if ( _dataSock != null )
496        {
497          _traces.trace("before STOP :"+_dataSock.toString()) ;
498          _dataSock.shutDown() ;
499        }
500        try {
501        _cmdSock.close() ;
502        } catch ( IOException e ) {
503         throw new ClientFtpError(" close CmdSock failed " +
504                                e.toString() ) ;
505        }
506     }
507 
508     // Give back current directory info
509     public String PRINTWD()
510     throws ClientFtpError
511     {
512       sendCommand("PWD") ;
513       // return bypassing FTP error code number
514       return(_lastMessage.substring(3));
515     }
516 
517     // set transfer mode to ASCII
518     public void ASCII()
519     throws ClientFtpError
520     {
521       sendCommand("TYPE A N") ;
522     }
523 
524     // set transfer mode to BINARY
525     public void BINARY()
526     throws ClientFtpError
527     {
528       sendCommand("TYPE I") ;
529     }
530 
531     private void buildPasvSocket( String msg227 )
532     throws ClientFtpError
533     {
534     int openPar = msg227.indexOf(_OPENPAR_) ;
535     int closePar = msg227.indexOf(_CLOSEPAR_) ;
536     String socketPort = msg227.substring(openPar+1,closePar) ;
537     StringTokenizer parser = new StringTokenizer(socketPort , _COMMA_ ) ;
538       try {
539         StringBuffer ipAddress = new StringBuffer( parser.nextToken()) ;
540         ipAddress.append(_DOT_) ;
541         ipAddress.append(parser.nextToken()) ;
542         ipAddress.append(_DOT_) ;
543         ipAddress.append(parser.nextToken()) ;
544         ipAddress.append(_DOT_) ;
545         ipAddress.append(parser.nextToken()) ;
546         try {
547           int p1 = Integer.parseInt(parser.nextToken()) ;
548           int p2 = Integer.parseInt(parser.nextToken()) ;
549           int port = (p1*256)+p2 ;
550           try {
551             _pasvSocket = new Socket(ipAddress.toString(),port) ;
552           } catch ( IOException g )
553           { throw new ClientFtpError("unexpected IOERR opening PASV socket : "+g.getMessage());}
554         } catch ( NumberFormatException e )
555         { throw new ClientFtpError("bad port on 227 msg : "+msg227 ) ; }
556       } catch ( NoSuchElementException f )
557       { throw new ClientFtpError("bad msg 227 format : "+ msg227 ) ; }
558     }
559 
560     // send a PASV request building a client connection if succeeded
561     // the connection will be used at RET time
562     public void PASV()
563     throws ClientFtpError
564     {
565       sendCommand("PASV") ;
566       if ( _lastReturn == FTP_PASV_OPEN ) // a 227 message is expected for PASV
567         buildPasvSocket(_lastMessage) ;
568       else if ( ( _lastReturn == FTP_PASV_CLOSE ) ||  // a 226 message may request closing the socket
569                 ( _lastReturn == FTP_PASV_CLOSE_ALTERNATE ) // a 250 is thrown by MVS
570               ) ;
571       else
572         throw new ClientFtpError("expecting 227,226 or 250  msg instead of : " + _lastMessage ) ;
573     }
574 
575     public String FTPCOMMAND( String command )
576     throws ClientFtpError
577     {
578       sendCommand(command) ;
579       return(_lastMessage) ;
580     }
581 
582     // CommandSocket Constructor
583     public CommandSocket( String ftpSrvName ,
584                           int commandPort   ,
585                           FtpClientListener listener
586                         )
587     throws IOException, ClientFtpError
588     // Connect to FtpServer and initialize streams
589     {
590       super( ftpSrvName , commandPort ) ;
591 
592       _rListener  = listener ;
593       _cmdStream  = new BufferedWriter(
594                          new OutputStreamWriter( getOutputStream() )
595                                       ) ;
596       _answStream = new BufferedReader (
597                          new InputStreamReader( getInputStream() )
598                                        ) ;
599 
600       getStatus() ;
601       if ( _lastReturn != FTP_SUCCESSFULL_CONNECTION )
602         throw new ClientFtpError("Connection error :" + _lastMessage );
603 
604       // Launch the DATA listener Thread
605       launchDATAListenerThread() ;
606 
607       // try a NOOP and SYST after successfull connection
608       // Use SYST result to get FTP SERVER OS
609       // not a good idea to do a NOOP here since server may refuse
610       // the operation until the user is logged in
611       // NOOP() ;
612     }
613   }
614 
615   /**
616 
617   DataSocket INNER CLASS is a threaded data transfert class used to
618   listen on FTP data port
619 
620   */
621 
622   class DataSocket extends Thread {
623 
624      private ServerSocket      _dataSocket ;
625      private boolean           _reader     ; // should we read or write data ????
626      private boolean           _stopping = false ;
627      private FtpClientListener _callBack   ;
628 
629        /**
630          LighWeight data Thread launched by main data thread to work on sockets
631        */
632        class LaunchDataThread extends Thread {
633 
634          private Socket  _lSock  ;
635          private boolean _reader ;
636 
637          public LaunchDataThread( Socket lsock , boolean reader )
638          {
639            _lSock  = lsock  ;
640            _reader = reader ;
641          }
642 
643          // Thread execution
644          // Listen waiting for incoming ftp connections
645          public void run ()
646          {
647            if ( _reader )
648            {
649               // Callback giving called back data stream to empty
650               try {
651                 _callBack.readData( _lSock.getInputStream() , _dataEvt );
652 
653               } catch( IOException e ) {
654                   _callBack.dataError( " Data thread reader build failed " +
655                                        e.toString() ,
656                                        _dataEvt
657                                       ) ;
658               }
659            }
660            else
661            {
662               try {
663                 _callBack.writeData( _lSock.getOutputStream() , _dataEvt  ) ;
664 
665               } catch( IOException e ) {
666                   _callBack.dataError( " Data thread writer build failed " +
667                                        e.toString() ,
668                                        _dataEvt
669                                      ) ;
670                 }
671            }
672            try {
673              _lSock.close() ;
674              _traces.trace( "local work Socket closed ") ;
675            } catch( IOException e ) {
676              _callBack.dataError( "Data thread close Socket failed " + e.toString(),
677                                   _dataEvt
678                                  )   ;
679            }
680          }
681        }
682 
683      // Actuate the data listener
684      public void set_callback( FtpClientListener ftpLstn    )
685      { _callBack   = ftpLstn             ;  }
686 
687      // public constructor
688      public DataSocket()
689      {
690        super() ;
691      }
692 
693      // Actuators
694      public final void setReader() { _reader = true ; }
695      public final void setWriter() { _reader = false; }
696 
697      // tell caller on which port we are listening
698      public final int getPort()
699      { return _dataSocket.getLocalPort() ; }
700 
701      // Set the stopping Flag on  and Connect to port to force
702      // connection to terminate(NB : this method is called by a different thread)
703      public void shutDown()
704      throws ClientFtpError
705      {
706        _stopping = true ;  // Force STOP listening
707        try {
708          // cmdSock should be queried since given computer may have
709          // multiple IP interfaces availables
710          Socket stopSock = new Socket( _cmdSock.getLocalAddress() , getPort() );
711        } catch ( IOException e )
712        {
713          throw new ClientFtpError("unable to connect dataSocket "+e.toString());
714        }
715      }
716 
717      /**
718         Thread execution
719         Listening  waiting for incoming SERVER side ftp connections
720      */
721      public void run ()
722      {
723      Socket lSock = null ;
724        _traces.trace( "data Socket thread started" ) ;
725 
726       try {
727         while ( ! _stopping  )
728         {
729           _dataSocket = new ServerSocket(0) ;
730           _traces.trace( "data Socket enters listening on :"
731                            + _dataSocket.getLocalPort()
732                          ) ;
733           lSock = _dataSocket.accept() ;
734           if ( _stopping )
735             _traces.trace( "Data Socket thread asked to terminate") ;
736           else
737           {
738             _traces.trace( "Data Socket accepting incoming connection") ;
739 
740             LaunchDataThread th = new LaunchDataThread(lSock,_reader) ;
741             th.start() ; // Start DATA reading or Writin process
742           }
743           _dataSocket.close() ;
744         }
745       } catch ( IOException e ){
746         // Activate the callback routine with a Null data and error Msg
747         _callBack.dataError(
748                   " main Data thread startup failed " + e.toString() ,
749                   _dataEvt
750                            ) ;
751       }
752 
753      }
754   }
755 
756 
757   /**
758     Bean compliant class constructor
759   */
760   public FtpClientSession()
761   {}
762 
763   /**
764     Init debugging on (Should be set before ftpInit call
765   */
766   public void set_parent( Ftp parent )
767   {
768     _parent = parent ;
769 
770     if ( _parent.is_debug() )
771     {
772       _traces.set_graphics( _parent.is_graphicalDebug() );
773       _traces.set_trace(true);
774     }
775   }
776 
777   public FtpTraces get_traces()
778   { return _traces ; }
779 
780   public final void trace( String message )
781   {
782     _traces.trace(message);
783   }
784 
785   // Initialize FTP server connection
786   public synchronized void ftpInit( String ftpSrvName  )
787   throws ClientFtpError
788   {
789     _ftpSrvName    = ftpSrvName ;
790     _dataEvt       = new FtpDataNotifier() ;
791 
792     try {
793       _cmdSock    = new CommandSocket(_ftpSrvName , _commandPort , null ) ;
794     } catch ( IOException e )
795     { throw new ClientFtpError(" Ftp socket Connection error " +
796                                e.toString() ) ;
797     }
798   }
799 
800   public String get_ftpSrvName()
801   { return _ftpSrvName ;  }
802 
803   /**
804 
805     Log in into FTP server
806 
807     @param userID user id connecting to FTP server
808     @param passwd associated password
809 
810   */
811   public synchronized void login ( String userID ,
812                                    String passwd
813                                  )
814   throws ClientFtpError
815   {
816     _cmdSock.LOGIN( userID , passwd , null ) ;
817     _currentUser = userID ;
818     _currentPsw  = passwd ;
819   }
820 
821   /**
822 
823     Log in into FTP server
824 
825     @param userID user id connecting to FTP server
826     @param passwd associated password
827 
828   */
829   public synchronized void login ( String userID ,
830                                    String passwd ,
831                                    FtpSessionOs ftpOs
832                                  )
833   throws ClientFtpError
834   {
835     _cmdSock.LOGIN( userID , passwd , ftpOs ) ;
836     _currentUser = userID ;
837     _currentPsw  = passwd ;
838   }
839 
840   /**
841 
842     use this method to reconnect a timed out session ; the
843     FTP session will be negociated using login provided userid and
844     passwords
845 
846  */
847   public synchronized void reconnectSession ()
848   throws ClientFtpError
849   {
850     if ( ( _currentUser == null ) || ( _currentPsw == null ) )
851       throw new ClientFtpError("undefined user/passwd : unable to reconnect " ) ;
852     ftpInit(_ftpSrvName) ;
853     _cmdSock.LOGIN( _currentUser , _currentPsw , _parent.get_ftpOs() ) ;
854   }
855 
856   /**
857 
858     Loging out Ftp Client Session
859 
860   */
861   public  synchronized final void stop()
862   throws ClientFtpError
863   { _cmdSock.STOP() ; }
864 
865   /**
866 
867     return current FTP server working directory
868 
869     @return current server working directory
870 
871   */
872   public  final String  getWorkingDirectory()
873   throws ClientFtpError
874   { return (_cmdSock.PRINTWD()) ; }
875 
876   /**
877     send a Site Command
878   */
879   public final String site( String siteValue )
880   throws ClientFtpError
881   {
882     return _cmdSock.SITE(siteValue);
883   }
884 
885   /**
886     send a DELE Command
887   */
888   public final boolean delete( String candidate )
889   throws ClientFtpError
890   {
891     return _cmdSock.DELETE(candidate);
892   }
893 
894   /**
895     send a RENAME Command
896   */
897   public final void rename( String from , String to )
898   throws ClientFtpError
899   {
900     _cmdSock.RENAME( from , to );
901   }
902 
903   public final void removeDirectory( String candidate )
904   throws ClientFtpError
905   {
906     _cmdSock.RMDIR(candidate);
907   }
908 
909   /**
910 
911     list command with callback
912 
913     @param callBack listener to be notified when list is ready
914 
915   */
916   public  synchronized void list( FtpClientListener callback )
917   throws ClientFtpError
918   {
919     _cmdSock.set_rListener(callback)  ;
920     if ( _parent.is_pasv() )
921       _cmdSock.LISTPASV() ;
922     else
923       _cmdSock.LISTPORT() ;
924   }
925 
926   /**
927 
928     Filtered file list operation
929 
930     @return the server side file list
931   */
932   public  synchronized Vector filteredList()
933   throws ClientFtpError
934   {
935     return ( _serverOS.ftpList(this) ) ;
936   }
937 
938   /**
939 
940     proceed with a change directory command on server side
941 
942     @param dirName directory location to point to
943   */
944   public synchronized void changeFtpSrvDir( String dirName )
945   throws ClientFtpError
946   {
947     _cmdSock.CWDIR(dirName) ;
948   }
949 
950 
951   /**
952 
953     proceed with a make directory command on server side
954 
955     @param dirName directory location to point to
956   */
957   public synchronized void newDirectory( String dirName )
958   throws ClientFtpError
959   {
960     _cmdSock.MKDIR(dirName) ;
961   }
962 
963   /**
964 
965     proceed with a remove directory command on server side
966 
967     @param dirName directory location to point to
968   */
969   public synchronized void deleFtpSrvDir( String dirName )
970   throws ClientFtpError
971   {
972     _cmdSock.RMDIR(dirName) ;
973   }
974 
975   /**
976 
977     change transfert mode to binary
978 
979     @param command ftp command to procees
980   */
981   public synchronized void ftpBinary()
982   throws ClientFtpError
983   {
984     _cmdSock.BINARY() ;
985   }
986 
987   /**
988 
989     execute a user entered FTP command
990 
991     @param command ftp command to procees
992   */
993   public synchronized String ftpCommand( String command )
994   throws ClientFtpError
995   {
996     return _cmdSock.FTPCOMMAND( command ) ;
997   }
998 
999   /**
1000
1001    change transfert mode to ASCII
1002
1003    @param command ftp command to procees
1004  */
1005  public synchronized void ftpAscii()
1006  throws ClientFtpError
1007  {
1008    _cmdSock.ASCII() ;
1009  }
1010
1011  /* IMPLEMENTING FtpConnection Interface */
1012
1013  /**
1014
1015    request info about the server OS hosting the FTP service
1016
1017    @return server side operating system name
1018  */
1019  public final String getOSFtp()
1020  {  return _serverOS.toString() ; }
1021
1022  public final String getOsDetails()
1023  { return _serverOS.getOsDetails() ; }
1024
1025  public String[] get_column_names()
1026  { return _serverOS.get_Column_Names() ; }
1027
1028  public boolean isLocal()
1029  { return false ; }
1030
1031  public void changeDirectory( String dirName )
1032  throws ClientFtpError
1033  { changeFtpSrvDir(dirName) ; }
1034
1035  public boolean isMVS()
1036  {  return _serverOS.isMVS() ; }
1037
1038  public void set_jesMode( boolean jesMode )
1039  { _serverOS.set_jesMode(jesMode) ; }
1040
1041  /* IMPLEMENTING FtpConnection Interface ENDS */
1042
1043  /**
1044
1045    FTP receive File Operation
1046
1047    @param fName remote file to be transfered locally
1048    @param callBack listener which will be notified when transfer completed
1049
1050  */
1051  public synchronized void getFile( String fName               ,
1052                                    FtpClientListener callback
1053                                  )
1054  throws ClientFtpError
1055  {
1056    _traces.trace("GET : " + fName );
1057    _cmdSock.set_rListener(callback)  ;
1058    if ( _parent.is_pasv() )
1059      _cmdSock.GETPASV(fName) ;
1060    else
1061      _cmdSock.GETPORT(fName) ;
1062  }
1063
1064  /**
1065
1066    FTP send File Operation
1067
1068    @param fName local file name to be put to server
1069    @param callBack listener which will be notified when transfer completed
1070
1071  */
1072  public synchronized void putFile ( String fName ,
1073                                     FtpClientListener callback
1074                                   )
1075  throws ClientFtpError
1076  {
1077    _cmdSock.set_rListener(callback)  ;
1078    if ( _parent.is_pasv() )
1079      _cmdSock.PUTPASV(fName) ;
1080    else
1081      _cmdSock.PUTPORT(fName) ;
1082  }
1083
1084  /**
1085  <PRE>
1086    this main method is used to test and demonstrate FtpClientSession
1087    class usage to tranfert file in and out.
1088
1089    usage of FtpClientSession class is straightforward :
1090
1091    here is the main test static class content :
1092
1093    *************************** CODE STARTS *************************
1094
1095    String host  = null ;
1096    String user  = null ;
1097    String passw = null ;
1098    String fName = null ;
1099
1100    System.out.println( "Starting ftp test" ) ;
1101    if ( argv.length  >= 1 )
1102      host  = argv[0] ;
1103    if ( argv.length  >= 2 )
1104      user  = argv[1] ;
1105    if ( argv.length  >= 3 )
1106      passw = argv[2] ;
1107    if ( argv.length  >= 4 )
1108      fName = argv[3] ;
1109
1110    try {
1111      Ftp ftp = new Ftp() ;
1112      ftp.set_ftpServerName( host );
1113      FtpClientSession myFtp = new FtpClientSession() ;
1114      myFtp.set_parent( ftp  ) ;
1115
1116      System.out.println( "Before init " ) ;
1117      myFtp.ftpInit(host) ;
1118      System.out.println( "Init done " ) ;
1119
1120      myFtp.login( user    , passw   ) ;
1121      System.out.println( "Login done " ) ;
1122
1123      FtpVectorListener fileList = new FtpVectorListener() ;
1124
1125      myFtp.list( fileList ) ;
1126
1127      System.out.println( "Ending ftp test part 1 " ) ;
1128
1129      if ( fName != null )
1130      try {
1131        DataOutputStream out = new DataOutputStream (
1132                               new BufferedOutputStream (
1133                               new FileOutputStream( fName )
1134                                                         )   ) ;
1135
1136
1137        for ( int ii = 0 ; ii < fileList.get_dataList().size() ; ii++ )
1138        {
1139          System.out.println( (String)( fileList.get_dataList().elementAt(ii))) ;
1140          out.writeBytes((String)( fileList.get_dataList().elementAt(ii))+"\n") ;
1141        }
1142        out.close() ;
1143      } catch ( IOException e ){
1144        System.out.println(  "Severe file access Error : " ) ;
1145        System.out.println(  e.getMessage() ) ;
1146
1147      }
1148
1149      Vector fileFilteredList = myFtp.filteredList() ;
1150      System.out.println( "Ending ftp test part 2 " ) ;
1151
1152      for ( int ii = 0 ; ii < fileFilteredList.size() ; ii++ )
1153        System.out.println( (FtpOsFile)( fileFilteredList.elementAt(ii) ) ) ;
1154
1155      // resend FileList local sored file back to caller
1156
1157      if ( fName != null )
1158        myFtp.putFile(fName , fileList ) ;
1159
1160      System.out.println( "Ending ftp test part 4" ) ;
1161
1162
1163      // reRead FileList once again
1164      if ( fName != null )
1165        myFtp.getFile(fName , fileList ) ;
1166
1167      System.out.println( "Ending ftp test part 3 " ) ;
1168
1169      for ( int ii = 0 ; ii < fileList.get_dataList().size() ; ii++ )
1170        System.out.println( (String)( fileList.get_dataList().elementAt(ii) ) ) ;
1171
1172      myFtp.stop() ;
1173
1174     } catch( ClientFtpError e )
1175    {
1176      System.out.println(  "Severe ftp error occured : " ) ;
1177      System.out.println(  e.getMessage() ) ;
1178    }
1179    System.out.println( "Ending ftp test :" ) ;
1180
1181    *************************** CODE ENDS   *************************
1182
1183    now let's explain it in details :
1184
1185    String host  = null ; ==> IP name or address of the host to connect with
1186    String user  = null ; ==> ftp user name
1187    String passw = null ; ==> associated password
1188    String fName = null ; ==> file name to transfer in or out
1189
1190    we will need 4 parameter to establish a FTP client connection, which
1191    are :
1192
1193      Ftp ftp = new Ftp() ;
1194      ftp.set_ftpServerName( host );
1195      ftp.set_userId( user ) ;
1196      ftp.set_passWord( passw );
1197      FtpClientSession myFtp = new FtpClientSession() ;
1198      myFtp.set_parent( ftp  ) ;
1199
1200    the two statement above proceed with FtpClientSession class initialization
1201    and should occur in the above specified order.
1202
1203    We then establish connection with the FTP host server
1204
1205    myFtp.ftpInit(host) ;
1206
1207    Before any operation we should log into the system providing username
1208    and password :
1209
1210    myFtp.login( user , passw   ) ;
1211
1212    we will then list the available files on server using a provided
1213    callback container class : FtpVectorListener which will store the
1214    FileList into a String vector :
1215
1216    FtpVectorListener fileList = new FtpVectorListener() ;
1217    myFtp.list( fileList ) ;
1218
1219    We will then write the File List into a local file and send it
1220    ovr the ftp connection and display it on standard locl output :
1221
1222      if ( fName != null )
1223      try {
1224        DataOutputStream out = new DataOutputStream (
1225                               new BufferedOutputStream (
1226                               new FileOutputStream( fName )
1227                                                         )   ) ;
1228
1229
1230        for ( int ii = 0 ; ii < fileList.get_dataList().size() ; ii++ )
1231        {
1232          System.out.println( (String)( fileList.get_dataList().elementAt(ii))) ;
1233          out.writeBytes((String)( fileList.get_dataList().elementAt(ii))+"\n") ;
1234        }
1235        out.close() ;
1236      } catch ( IOException e ){
1237        System.out.println(  "Severe file access Error : " ) ;
1238        System.out.println(  e.getMessage() ) ;
1239      }
1240      Vector fileFilteredList = myFtp.filteredList() ;
1241      System.out.println( "Ending ftp test part 2 " ) ;
1242
1243      for ( int ii = 0 ; ii < fileFilteredList.size() ; ii++ )
1244        System.out.println( (FtpOsFile)( fileFilteredList.elementAt(ii) ) ) ;
1245
1246   We now send the file over the FTP connection , the transfer messages
1247   beeing strored into the fileList string vector :
1248
1249      if ( fName != null )
1250        myFtp.putFile(fName , fileList ) ;
1251
1252   We after do the reverse operation transfering the file back :
1253
1254   if ( fName != null )
1255        myFtp.getFile(fName , fileList ) ;
1256
1257  </PRE>
1258  */
1259  public static void main ( String argv[] )
1260  {
1261  String host  = null ;
1262  String user  = null ;
1263  String passw = null ;
1264  String fName = null ;
1265  String binFname = null ;
1266
1267    System.out.println( "Starting ftp test" ) ;
1268    if ( argv.length  >= 1 )
1269      host  = argv[0] ;
1270    if ( argv.length  >= 2 )
1271      user  = argv[1] ;
1272    if ( argv.length  >= 3 )
1273      passw = argv[2] ;
1274    if ( argv.length  >= 4 )
1275      fName = argv[3] ;
1276    if ( argv.length  >= 5 )
1277      binFname = argv[4] ;
1278
1279    try {
1280      Ftp ftp = new Ftp() ;
1281      ftp.set_ftpServerName( host );
1282      FtpClientSession myFtp = new FtpClientSession() ;
1283      myFtp.set_parent( ftp ) ;
1284
1285      System.out.println( "Before init " ) ;
1286      myFtp.ftpInit(host) ;
1287      System.out.println( "Init done " ) ;
1288
1289      myFtp.login( user    , passw   ) ;
1290      System.out.println( "Login done " ) ;
1291
1292      FtpVectorListener fileList = new FtpVectorListener() ;
1293
1294      myFtp.list( fileList ) ;
1295
1296      System.out.println( "Ending ftp test part 1 " ) ;
1297
1298      if ( fName != null )
1299      {
1300        try {
1301          File file = new File(fName) ;
1302          if ( ! file.exists() )
1303          {
1304            DataOutputStream out = new DataOutputStream (
1305                                   new BufferedOutputStream (
1306                                   new FileOutputStream( fName )
1307                                                            )
1308                                                        ) ;
1309
1310
1311            for ( int ii = 0 ; ii < fileList.get_dataList().size() ; ii++ )
1312            {
1313              System.out.println( (String)( fileList.get_dataList().elementAt(ii))) ;
1314              out.writeBytes((String)( fileList.get_dataList().elementAt(ii))+"\n") ;
1315            }
1316            out.close() ;
1317          }
1318        } catch ( IOException e ){
1319          System.out.println(  "Severe file access Error : " ) ;
1320          System.out.println(  e.getMessage() ) ;
1321        }
1322      }
1323
1324      Vector fileFilteredList = myFtp.filteredList() ;
1325      System.out.println( "Ending ftp test part 2 " ) ;
1326
1327      for ( int ii = 0 ; ii < fileFilteredList.size() ; ii++ )
1328        System.out.println( (FtpOsFile)( fileFilteredList.elementAt(ii) ) ) ;
1329
1330      // resend FileList local sored file back to caller
1331
1332      if ( fName != null )
1333        myFtp.putFile(fName , fileList ) ;
1334
1335      System.out.println( "Ending ftp test part 4" ) ;
1336
1337
1338      // reRead FileList once again
1339      if ( fName != null )
1340        myFtp.getFile(fName , fileList ) ;
1341
1342      System.out.println( "Ending ftp test part 3 " ) ;
1343
1344      for ( int ii = 0 ; ii < fileList.get_dataList().size() ; ii++ )
1345        System.out.println( (String)( fileList.get_dataList().elementAt(ii) ) ) ;
1346
1347      // checking for binary data tranferts
1348      if ( binFname != null )
1349      {
1350        try {
1351          File myFile = new File(binFname) ;
1352          int fileSize = -1 ;
1353          if ( myFile.isFile() )
1354            fileSize = (int) myFile.length() ;
1355          if ( fileSize != -1 )
1356          {
1357            byte array[] = new byte[fileSize]  ;
1358            BufferedInputStream toFtpPut = new BufferedInputStream(
1359                                             new FileInputStream( binFname )
1360                                                                 ) ;
1361            toFtpPut.read( array , 0 , array.length ) ;
1362            FtpBytesListener myTransmitter = new FtpBytesListener() ;
1363            myTransmitter.set_dataList( array ) ;
1364            myFtp.ftpBinary();
1365            myFtp.putFile( binFname , myTransmitter ) ;
1366
1367            myFile.delete() ; // clear file locally
1368            myTransmitter = new FtpBytesListener() ;
1369            myFtp.ftpBinary();
1370            myFtp.getFile( binFname , myTransmitter ) ;
1371
1372          }
1373          else
1374            System.out.println("unable to proceed file : " + binFname ) ;
1375        } catch ( IOException e )
1376        { System.out.println("IOERROR transferring binary file over FTP : " + e.getMessage() ) ; }
1377      }
1378
1379      myFtp.stop() ;
1380
1381     } catch( ClientFtpError e )
1382    {
1383      System.out.println(  "Severe ftp error occured : " ) ;
1384      System.out.println(  e.getMessage() ) ;
1385    }
1386
1387    Thread.currentThread().getThreadGroup().list() ;
1388    System.out.println( "Ending ftp test :" ) ;
1389  }
1390}