Nicolas Delerue
McGill University
308-573B
(Professor Ratzer)
A Java-Based
FTP software
Winter 1998
Table of Content:
1Foreword 4
2A Brief overview of Java 5
2.1The Java Idea 5
2.2The Java Virtual Machine 6
2.3Some adaptations I did to the JDK 7
3A brief overview of the FTP standard 7
3.1The Telnet standard and the Network Virtual Terminal 8
3.2The FTP standard 8
3.3Comparison between the NVT and the JVM 10
4The software 10
5This is still a work in progress 15
6Portability 16
7Conclusion 17
8Appendix 18
8.1Some useful URLs and bibliography 18
8.2The source code 19
8.3Acknowledgements 71
I often transfer data on the Internet and thus I often use FTP software. On my own computer (a PC running under Windows 95), I have found a few useful software, but none of them were freeware. Under UNIX the situation is worse, because the only FTP software installed on most of the UNIX systems has no graphical interface and is not really user friendly (you can not even delete a character you just typed). As in High Energy Physics (my main field of study), we sometimes have to transfer up to 10Go in a night, I thought it would be great to write a user-friendly FTP software.
I have learned a few computer languages, mainly physics oriented such as Fortran 77 and 90, more recently, I learned C here at McGill, but I wanted to learn a graphical language. Even if I had read about it, I had never had the opportunity of writing a program in Java. As Java is said to be portable on all kinds of computers, it meets the universality I want for my software. I also often writes Web sites, and therefore I wanted to learn Java. That is why I wrote my software in Java.
Within the last few years, Java has become one of the most famous programming languages. This is due to some of the key ideas of the Java Language. One of its most important features is portability: one of the Java mottos is “Write once, run everywhere”. Once you have written an application, you should be able to run it on any kind of computers and even on some other electronic devices powered by Java, such as cellular telephones, microwaves oven or VCR. This feature may seem not so important for people who use to write code only for PC’s, but when you want to write code for UNIX systems, it is important to be sure that your application will run anywhere. Java provides you this, without even the need of testing your software on all these platforms!
Another important feature of Java is network-oriented Java is the first language to provide in its core many useful network tools such has direct addressing of a network socket through the URL of the remote host, detection of malformed URLs…
Java is also adapted to the multitask technologies and within the same application, some components can run independently of the others. These are called threads and provide more flexibility to the final product.
A last important feature of Java is that it is a graphical language that provides easy to use tools for both MS-Windows and X-Windows programming.
But as Java is a very recent language, it is still evolving, some adaptation are done every weeks an it is very important to often connect to Java’s web site (see the Bibliography) to known if new bugs have been detected or fixed and to download new releases of the JDK when necessary (but this means a 10 Megs download!) or also to submit new bugs when I thought to have detected some...
I started with JDK 1.0 that was on a CD-ROM I got from a book, but soon I decided to move to JDK 1.1.0.
Later I decided to use powerful new graphical tools released by sun in February, and know as the JFC (Java Foundation Class) or the swing components but these required JDK 1.1.5, some I changed once more of compiler.
As I would like to implement a help to my software, I will need to use the JavaHelp system, but this will only be available with the release 1.2 (actually available for testing), I will have to change once again of compiler…
To ensure the universal portability between on a huge diversity of platforms, the programmer must know at least how to access the different components of the machine, and where he/she can expect an input to come from and where he/she can send outputs. Therefore, the Java standard defines a Java Virtual Machine (JVT) that is the minimum that must have all platforms on which exists. The JVT includes only two things: an input and an output.
But, it is important to know that these two things are not the standard input (a keyboard) and output (a printer) used by most of the programming languages and by the Network Virtual Terminal (see below).
In the JVT the input are provided by a pointing device such as a mouse and the output by a graphical display area. This choice has been made by sun because these input/output are more likely to be on any kind of system rather than a keyboard and a printer. For example, a touch-screen does not have a keyboard and a Java-applet is not able to write on a printer.
The use of some instruction like System.out.println() (a basic instruction that sends a string on the output) for example, is not “100% pure Java”, because on some automated systems this instruction will fail due to the lack of device where to display the string without formatting it.
After my first month of Java-Programming, I found this language was great, except one thing: the lack of pre-processor. Till this year I had never used languages with pre-processor, but when I learned C in the Fall session, I really enjoyed the features of the pre-processor and later when I wrote the web server of the McGill Daily Français, I made an intensive use of the C pre-processor.
The lack of pre-processor was a problem for me as I expected to translate this software at least in German and French and I know that a translation is really easier when all the texts to translate are gathered at the same place. The translation may also require some changes in the size of some dialog boxes (a text with the same meaning do not have the same length in all languages, you can check that just by having a look at the bilingual Canadian constitution) so these size must also be all determined at the same place. Thus I choose to re-use the pre-processor available with gcc (gnu C compiler) and made a little script (jav.bat) that automatically pre-processes my files and compile them:
@echo off
cpp -P %1.java > c:\disk_f\programmation\java\compilation\%1.java
javac -g c:\disk_f\programmation\java\compilation\%1.java
copy c:\disk_f\programmation\java\compilation\%1.class
(Where c:\disk_f\programmation\java\compilation\ is a directory where the pre-processed files are stored; gcc and javac must both be in the path)
Opposed to the brand new Java language, the Internet protocols are more than 10 years old. This means that they are based on the technology that was available and commonly spread at that time…
Nearly all Internet protocols rely on the Telnet Protocol Specification, as described by J.Postel and J.Reynolds in the RFC 854.
The most important thing that the Telnet protocol does is the specification of the minimum requirements of any machine that implements these protocols. These requirements define what is called the Network Virtual Terminal (NVT). An NVT is the minimum unit required communicating over the Internet. It has:
-A keyboard or any such input device able to enter characters
-A printer or any such output device able to display/print characters.
The definition given in the FRC 854 is:
“An NVT is an imaginary device which provides a standard, network-wide, intermediate representation of a canonical terminal.
[…]
The NVT has a printer and a keyboard. The printer responds to incoming data and the keyboard produces outgoing data which is sent over the TELNET connection”
It is worth to note that for example any UNIX process may be considered as an NVT, so communications using the Internet protocols can be done between humans, but also between a human and a process or between two processes.
The telnet specification also defines how Telnet commands must be embedded within the data (here data may refer to both real data or simply to command transmitted by a “higher level” protocol such as the FTP protocol).
The FTP standard defines the set of command that must be used between two NVT to initiate transfers of data such as files. It is worth to know (I spent a long time before finding that), that the data are not transferred using the communication channel established between the two NVT, but for each data transfer, a data transmission channel is opened, used to transmit raw and then closed to signify the End Of File. This channel is called the Data Port (DTP), whereas the normal NVT communication channel is the Command Port. It is also important to know that a new data port must be opened prior to each data transmission this is done with the command PORT.
In addition to the standard NVT requirement, any FTP host must have access to a file system. The standard has been built assuming that the file system has a tree structure as does UNIX, Multics or MS-DOS.
Thus, the commands are split between different groups:
Access control commands that let the user login, enter his/her password…
Transfer Parameter Commands, these commands let the user specify the DTP, the transmission mode (binary, ASCII or EBCDIC).
Service commands that are used to manage the connection (Abort, Reset…) or to initiate file transfer.
To these commands corresponds a set of specified answer. These answers are made of a tree digit number followed by a human-readable message. The first digit specifies the completion of the command:
1yz Positive preliminary reply: the command sent by the user was successfully understood and an action started. Often this answer means that the user has to check his DTP to receive data.
2yz Positive Completion reply: The request as been successfully completed.
3yz Positive Intermediate reply: the request has been understood, but the server needs more information (a password for example) before processing the command.
4yz Transient Negative Completion Reply: The command could not be processed at the moment, but the user is encouraged to try again… For example, if the server shuts down after 900 seconds it sends a 421 code that means that the next command will not be understood, but if the user logs back in and tries again, the command may be understood.
5yz Permanent Negative Completion Reply: The command was not accepted (eg: command not understood, file not found…)
After the description of both the Java Virtual Machine and the Network Virtual Terminal it appears that the have different nature:
One is based on a character-oriented communication whereas the other is based on an event-oriented communication.
The conversion between these two different philosophy has sometimes been hard especially when the FTP answer where specified to be aimed “for human user only” and thus not for automated processing whereas their display on the JVM required a processing (this worst problem appeared with the LIST command that was the only way of having accurate information about the files, but which is not for automated processing).
The same problem appears with the Network Computers (NC) that are supposed to be computers of the future: as they are installed on the network, they require a character oriented communication, but end user more and more require nice graphical display, these NC have to internally run event oriented communication. Even if some problems may appear, I think that in this context, Java provides a good set of tools for these “translations” and it is a good language for such computers.
After the description of the main tools on which my software relies, I will now describe it.
As the aim of an FTP software is to transfer files between computers it must provide a way to connect onto these computers. As I think that sometimes one may need to transfer files from one computer to several others, I have not limited the number of computers to which one can be connected at the same time.
Each computer will be handled the same without consideration of this computer being the local computer or a remote computer. For each of these computer a “connection window” is opened and each computer is handled independently.
This feature may be very useful for somebody who wants to transfer files between two remote systems: even if the local internet connection is very bad or slow (DAS connection for example), the user will be able to transfer data between the remote systems at the highest speed possible between these two host (with the FTP software I have tested under win 95 you always have to download the file on your hard disk and then upload it on the target host; if you have a DAS connection and want to transfer files of the scale of the megabyte, this may take a while…).
To let the user connect to a host, a list of recorded host is displayed in each “connection window” of the software’s main screen. This list of ‘predefined host’ will be read from the .netrc file, as the basic UNIX FTP software usually does it. To preserve compatibility and universality, the password will not be encrypted in this file (exactly as in the usual .netrc file) this is also required by the fact that as French citizen I am not allowed to write cryptographic procedures and them bring them back home!
Here is a sample of .netrc file (more information can be found in the UNIX man pages):
machine willy.cs.mcgill.ca
name Willy
login nicolas
password xxxxx
machine lisa.cs.mcgill.ca
name Lisa
login nicolas
password xxxxx
machine criens.u-psud.fr
login p99deler
password xxxxx
machine korsika.desy.de
login delerue
password xxxxx
machine abraham.ugrad.physics.mcgill.ca
login nicolas
password xxxxx
Two entries are added to this list. The first one is “connect to a local host” and the second one is “connect to another host”.
As I have chosen to deal with the local host exactly as I does with the remote ones, there will be no specified window for the local host and thus, it was necessary to allow the user define where he/she wants to connect to the local host.
As the user may want to connect to hosts he never connected to before, I added the functionality “connect to another host”. When double-clicked this option displays a dialog box where the user has to enter his/her login and password and the remote host name. After, the user may click on three different buttons. The first one will initiate the connection and add this host name to .netrc The second one will simply connect to the remote host and the third one will simply add the host’s name to the .netrc (but the “add to the .netrc” feature is not implemented at the moment).
The background of the non-connected “connection window” is green whereas it is blue for connected windows.
For a non-connected window, the tool bar only offer one possibility: closing the current “connection window”, this may be useful if one just want to browse the files on a remote host or if after connecting to many different hosts one wants to reduce the number of windows.
The application menu also offers the possibility to connect to a remote host. When a host is selected in this menu, the first non-connected window is connected to the specified host. If all windows are connected, a new one is created.
The menu also offers two other topics: “main” and “help”. Under main, all the customisation features will be implemented later. At the moment, only the “quit” option is enabled.
The help menu is also under construction, especially because I am waiting for the release of a stable version of JDK 1.2 (at the moment only release are available with pre-specification, so I preferred to wait).
In the help menu, one can also access the “credits” and the registration explanations (I will probably release this software as a shareware for the windows version when I will have added a few more features and found a .exe generator; the retail price will probably be something like CA$10.00 or 6.00 Euro (the future European Currency Unit, starting next year).
A
screen copy of the main screen of the application,
before any
connection.
Once a connections has been established, the background colour if the connection window becomes blue and a tree containing all the files of the login directory is displayed.
To display this, the list of files returned by the NLST FTP command is sorted alphabetically then the LIST command is sent and its answer is analysed. As there are no specification for the LIST command answer’s format (except that this command is not aimed at an automated processing), the software has to make guesses to identify the size of the file and the access right (in the case of a UNIX like structure). If the directory is empty, then a file named “..” is shown the let the user know that the directory has been expanded successfully but is empty.
Once these elements have been found, a new list is returned with the directories first and then the files.
Files can be selected and then dragged to another connection window. If this window is connected, the two host will communicate together to initiate the transfer of all selected files. At the moment, the transfer of directories with all their files is not implemented, but this will be done soon as it seems to be quiet easy to do.
By double-clicking on the a directory folder, one can see the content of the directory (at the moment when one doubles click on a directory for the first time, the tree is rebuilt with all its branches collapsed and one needs to double-click a second time to see the content of this directory).
After the connection, a tool appears at the top of the connection window. This toolbar contains the following items: “updir” that let the user browse the upper directory, “Refr” that let the user refresh the current list of display (but with the same problem than for the directory expanding: the tree is rebuilt with all its branches collapsed…), “Disconnect”, to let the user terminate a connection (after clicking on this button, the connection window returns to its not-connected state), “Delete” that delete all selected files and empty directories and “Close” that terminates the connection (sends the “QUIT” FTP command to the remote host) and close the connection window.

A screen copy of the application with two “connection windows”
connected to the local host (left) and to a remote host (right)
On
this picture, one can see the file trees with some directories
expanded (images and images\photos on the local host and vero for the
remote host)
Another important feature that I gave to my code is that by the use of an included file with all text and text related constant, it will be very easy to translate. As the High-Energy Physics community is made of people from various country, it is nicer to be able to offer them (and also to general public) software in their own language. Easy translation is also (I think) a way to save cost when trying to make the software comply with national/provincial laws such as bill 101 in province of Québec.
As many FTP server automatically disconnect an host that has not sent any command during 900 seconds, the application automatically logs back in when such disconnection message is sent. (At the moment this functionality still experience some problems)
I believe that a software as a piece of fine art, is never completely finished, more features can always be added or parts of the algorithm be improved.
Here is a first release of the software that does what I wanted: transfer files between computers. However, I am not satisfied, and I will improve this application when I will find time to do so (and prior to releasing as shareware).
The things I would like to improve are:
The addition of the host name to the .netrc file when requested
The possibility of specifying a specific login directory for each host recorded in the .netrc
The possibility of bundling hosts together, for example, if you often transfer files from a server A to a server B, it would be great if by a single click you could login to both A and B
Automatically expand the file tree when its content is updated
Make all the files of a directory to be transferred/deleted when the directory’s folder is transferred/deleted
Fixing the resizing problem when a connection window is closed or opened
Fixing the auto re-login feature
Resize some dialog boxes and changes some colours
Add progress bar on all FTP commands (at the moment the user can not know what is going on), and also add dialog boxes show error messages that may be sent by the remote host.
Checking the pieces of code that still use the JDK 1.0 API and rewrite them using the JDK 1.1 or 1.2 standard.
In addition, there are some features that I think would be nice to add:
Possibility of creating directories and to rename files
Display of a diagram showing how much space is used by each directory and its content (including subdirectories), this feature will be a graphical display of what the UNIX command “du” does (this will be very useful to find where all the space on my hard disk has gone!).
Automatic download of an HTML file and all files referred by this file on the same server (other HTML files and pictures referred by tags such as <A HREF=…> or <IMG SRC=…>).
I am also open to any suggestions that could be made by any FTP software user… (I have a permanent e-mail where I can receive such suggestions at nico@backpackers.com ).
Thanks to the “Write once, run everywhere” rule, as the FTP software is running on my computer, it should be running on any computer of any kind without any problems! To have an idea of the computers for which it is possible to find a Java Virtual Machine interface, one can have a look on Java’s web site at the portability list:
http://java.sun.com/cgi-bin/java-ports.cgi
If I trust what Java as shown at the JavaOne conference (and there are no reasons not to trust it), my application will also soon be able to run onto devices such as a TV, a microwave or even a cellular phone… May be, thanks to my software, one will some day be able to download cooking recipes from his Java-enhanced microwave…
But, even if the future looks bright, when I tried to generate a small embedded stand alone .exe file I discovered that the execution of any Java software made with the JDK requires the installation, by the end-user, of either the JDK (more than 10Mo compressed) or the JRE (only 3 Mo!). And as I use JFC, one will need to install the swing kit that uses 7.5 additional Mo, or at least the classes included with it (3Mo).
So, I tried to use some commercial software that claim to be able to generate .exe file from Java programs. After trying a few trial versions of these softwares, I discovered that none of them is compatible with the JDK 1.1.5 and the JFC.
So, yes, my software is very portable, but one needs to bring more than 10Mo of file with a software that does not weight more than a few hundreds by itself… (even on skinner, the SOCS’s computer on which the JDK is installed, my software can not run due to the fact that the JFC are missing…)
According to the information released by sun in the Java newsgroups, they should release soon a compiler that will be able to generate .exe files. I am looking forward for this in order to be able to release my software as stand alone application.
The speed of the application is also one of my big concerns: at the moment, the application runs quiet slowly. For most of the task it is not a problem, because a FTP transfer is always slow due to the slowness of Internet, but, when one has to wait several seconds before a window appears or the display is refreshed, it is may be too much… Java claims that “Just In Time” compiler will be able to boost the speed of the applications. I hope so…
When I started this project, I wanted to learn Java as a tool to make fun applets on my web pages and a tool to build graphical application on top of the user-not-so-friendly applications that we usually use in High Energy Physics, a kind on the icing on the top of the cake, because I thought that particle physicist will always have to write there software in Fortran and the data recording interfaces in assembler languages.
Four month later I still believe that Java is a great graphical language, but I also discovered that this language is adapted to automated systems programming and small data acquisition devices. So, I believe that Java may be also a programming language that I may need as particle physicist when I will need to program such devices.
During this project, I also learned lots of stuff about the Internet and the Internet protocols. As Internet is an ever-growing thing that will probably play an increasing role in all parts of our life, I probably acquired a knowledge that will be very worth in a few years…
It would be unbelievable to do Java Programming without having a glance at the web site where Java is born: http://java.sun.com
Sun and JavaSoft provides also a place where Java Developers can meet. It is called the “Java Developers Connection” and it is accessible at http://developer.javasoft.com the access of the site is restricted to members, but membership is free and without any obligations…
The Java Language Specifications are available at http://java.sun.com/docs/books/jls/html/index.html
To learn Java it can be useful to have a look at the Java Tutorial, made by sun http://java.sun.com/docs/books/tutorial/getStarted/index.html
Reference
pages about the different classes provided with the JDK are provided
at:
http://java.sun.com/products/jdk/1.1/docs/api/a-names.html
And they can be downloaded with the JDK (more than 10 Megs!) at http://java.sun.com/docs/books/tutorial/information/download.html and many other useful documents related to the Java language and its specification can be found at http://java.sun.com/docs/index.html
More information about the swing components can be found at http://java.sun.com/docs/books/tutorial/ui/swing/
The rules to be followed to obtain the 100% Java Certification are gathered in the 100% Pure Java Cookbook at http://www.suntest.com/100percent/cpd/doc/cbook/cookbook.html
Many interesting applications or devices compatible with the Java technology have been shown at the JavaOne conference in April 1998 and they are gathered in the JavaTechTown:
http://java.sun.com/features/1998/04/javatechtown.html
While developing this software I also used a book (in French): “Java, le livre d’Or” by P.Longuet, published in France by Sybex. This book has been very useful for me to learn Java and also as reference book while internet was shut down during the Ice Storm, but even if it has been published in 1996, this book only covers the JDK 1.1 release and thus is already out-of-date…
The
RFC 959 “FTP specification” and RFC 854 “Telnet Protocol
Specification”, both by J.Postel et al. have also been very
useful reference documents. Both can be found at:
http://www.cis.ohio-state.edu/hypertext/information/rfc.html
Here is a sample of the source code as of end of April 1998, I know that some of the tricks I need are not the best I could have done, I need to add comments to some parts or to rewrite some parts, but the following code is working…
Only the most important classes and the constants file are provided. All other classes can be found on the Disk included with this report (the application uses a total of 15 classes plus a file of constants).
//#include "c:\disk_f\programmation\Java\FTP\consts.java"
#include "c:\disk_f\programmation\Java\FTP\textes.java"
import java.io.*;
import java.util.*;
import java.awt.*;
import connections.*;
import host_list.*;
import dialg.*;
import com.sun.java.swing.*;
import com.sun.java.swing.tree.TreePath;
/**
* the NicoFTP class in the class that creates the graphical interface of the application
*/
public class NicoFTP extends Frame
{
Dimension winSize; /** the size of the window */
Vector vectConnections = new Vector(); /** All connections are gathered in a vector */
connections currentConnection; /** Here we store the current connection */
// connections target,source; /** the connections that exchanged data in a dragg operation */
host_list hostRecords;
DISPLAY_TYPE display;
GridBagConstraints dispConstraints;
boolean dragged; /** remembers if an object has been dragged recently */
//defining the constructor
public NicoFTP()
{
int i;
//defining the display
display=new DISPLAY_TYPE();
//display=new DISPLAY_TYPE(4,4);
// display=new DISPLAY_TYPE(1,4*INITIAL_CONNECTIONS);
dispConstraints = new GridBagConstraints();
setLayout(display);
dispConstraints.fill=GridBagConstraints.NONE; /* The empty space is left empty */
dispConstraints.anchor=GridBagConstraints.CENTER; /* The components are centered */
setTitle(TITRE);
winSize=new Dimension(INITIAL_WIDTH,INITIAL_HEIGHT);
setSize(winSize);
setResizable(true);
hostRecords = new host_list();
//definig the Menu
MenuBar mb = new MenuBar();
Menu m1= new Menu (MENU_MAIN);
mb.add(m1);
{
Menu i11 = new Menu(MENU_MAIN_PARAMS);
m1.add(i11);
{
MenuItem i111 = new MenuItem(MENU_MAIN_PARAMS1);
i11.add(i111);
MenuItem i112 = new MenuItem(MENU_MAIN_PARAMS2);
i11.add(i112);
}
MenuItem i12 = new MenuItem(MENU_MAIN_QUIT);
m1.add(i12);
}
Menu m2= new Menu (MENU_CONNECT);
mb.add(m2);
{
Vector list; /* we will get the list of the host */
int hostIndice; /* and we will display them, one by one, so we will need a counter */
MenuItem i21 = new MenuItem(MENU_CONNECT_NEW);
m2.add(i21);
MenuItem i22 = new MenuItem("-");
m2.add(i22);
/* MenuItem i22l1 = new MenuItem(MENU_CONNECT_LOCAL);
m2.add(i22l1);
*/
hostIndice=0;
list = hostRecords.hostList();
while(hostIndice<list.size())
{
MenuItem hostItem = new MenuItem((list.elementAt(hostIndice)).toString());
m2.add(hostItem);
hostIndice++;
}
}
Menu m3 = new Menu(MENU_HELP);
mb.add(m3);
{
MenuItem i31 = new MenuItem(MENU_HELP_FTP);
m3.add(i31);
MenuItem i32 = new MenuItem(MENU_HELP_CREDITS);
m3.add(i32);
MenuItem i33 = new MenuItem(MENU_HELP_BUGS);
m3.add(i33);
MenuItem i34 = new MenuItem(MENU_HELP_REG);
m3.add(i34);
}
// display of the menu
setMenuBar(mb);
//Defining the sub-frames (connections)
for (i=0; i< INITIAL_CONNECTIONS; i++)
{
currentConnection = new connections(winSize.width/(INITIAL_CONNECTIONS),winSize.height-MENU_HEIGHT,i*(winSize.width/(INITIAL_CONNECTIONS)),MENU_HEIGHT,hostRecords,display,this);
vectConnections.addElement(currentConnection);
}
show(); /* and finally we display the window */
} // end of the constructor
//events handler
//events related to the menu
public boolean action(Event evt, Object arg)
{
Vector list; /* we will get the list of the host */
int hostIndice=0; /* and check them one by one */
if (evt.target instanceof MenuItem)
{
String Cde = (String)arg;
//Main menu
if (Cde.equals(MENU_MAIN_QUIT))
System.exit(0);
if (Cde.equals(MENU_MAIN_PARAMS1))
NotAvailable();
if (Cde.equals(MENU_MAIN_PARAMS2))
NotAvailable();
//Connections
if (Cde.equals(MENU_CONNECT_NEW))
{
addConnection();
}
list = hostRecords.hostList();
while(hostIndice<list.size())
{
if(Cde.equals((list.elementAt(hostIndice)).toString()))
{
int i=0;
AFF(("connection "+((list.elementAt(hostIndice)).toString())));
while( i < vectConnections.size())
{ /* we look for the first non connected connection */
currentConnection=(connections) vectConnections.elementAt(i);
if(currentConnection.connected)
{
i++;
currentConnection=null;
}
else
{
i=vectConnections.size();
AFF(("trouve"));
}
} /* while */
if(currentConnection==null)
{
currentConnection=addConnection();
}
if(currentConnection!=null)
{
AFF(("hostIndice "+hostIndice));
currentConnection.openConnection(hostIndice);
}
}
hostIndice++;
}
//Help
if (Cde.equals(MENU_HELP_FTP))
NotAvailable();
if (Cde.equals(MENU_HELP_CREDITS))
credits();
if (Cde.equals(MENU_HELP_BUGS))
bugs();
if (Cde.equals(MENU_HELP_REG))
registration();
}
return(true);
}
//credits
public void credits()
{
infoBox credits = new infoBox(this,CREDIT_WIDTH,CREDIT_HEIGHT,CREDIT_TITLE,CREDIT_TEXT);
}
//bugs
public void bugs()
{
infoBox bugs = new infoBox(this,BUGS_WIDTH,BUGS_HEIGHT,BUGS_TITLE,BUGS_TEXT);
}
//registration
public void registration()
{
infoBox reg = new infoBox(this,REG_WIDTH,REG_HEIGHT,REG_TITLE,REG_TEXT);
}
//NotAvailable
public void NotAvailable()
{
infoBox na = new infoBox(this,NA_WIDTH,NA_HEIGHT,NA_TITLE,NA_TEXT);
}
// Events in case of Hard close of the window
public boolean handleEvent(Event evt)
{
if ((evt.id == Event.WINDOW_DESTROY)||((evt.id == Event.ALT_MASK)&&(evt.id == Event.F4)))
{
destroy();
return(true);
}
else
{
// AFF(("event: "+evt.id));
}
return super.handleEvent(evt);
}
/**
* update is a method that check for each connection if the current display is up-to-date
*/
protected void upDate()
{
Component c;
GridBagConstraints dispConstraints = new GridBagConstraints();
setLayout(display);
JToolBar tb;
removeAll(); /* removes all the components of this window */
for (int i=0; i < vectConnections.size(); i++)
{
currentConnection=(connections) vectConnections.elementAt(i);
dispConstraints = new GridBagConstraints();
dispConstraints.fill=GridBagConstraints.NONE;
dispConstraints.gridx=i;
dispConstraints.gridy=0;
dispConstraints.gridheight=1;
dispConstraints.gridwidth=1;
dispConstraints.weightx=1.0;
dispConstraints.weighty=1.0;
dispConstraints.insets=new Insets(0,0,0,0);
tb=currentConnection.getToolBar();
if(tb!=null)display.setConstraints(tb,dispConstraints);
if(tb!=null)add(tb);
dispConstraints.fill=GridBagConstraints.NONE;
c=currentConnection.compo();
dispConstraints.gridx=i;
dispConstraints.gridy=1;
dispConstraints.gridheight=1;
dispConstraints.gridwidth=1;
dispConstraints.weightx=1.0;
dispConstraints.weighty=1.0;
dispConstraints.insets=currentConnection.insets;
display.setConstraints(c,dispConstraints);
add(c);
}
} /* upDate */
/**
* addConnection is a method that adds a connection in the connections' list
*/
public connections addConnection()
{
int i=vectConnections.size();
currentConnection = new connections(winSize.width/(i),winSize.height-MENU_HEIGHT,i*(winSize.width/(i)),MENU_HEIGHT,hostRecords,display,this);
vectConnections.addElement(currentConnection);
repaint();
return currentConnection;
}
// The graphical part of the window
public void paint(Graphics g)
{
rePaint(g);
} /* paint */
/**
* rePaint repaints the current graphical Display
*/
public void rePaint(Graphics g)
{
winSize=getSize();
setBackground(Color.gray);
for (int i=0; i < vectConnections.size(); i++)
{
currentConnection=(connections) vectConnections.elementAt(i);
currentConnection.setSize(winSize.width/(vectConnections.size()),winSize.height-MENU_HEIGHT,i*(winSize.width/(vectConnections.size())),MENU_HEIGHT);
currentConnection.draw(g);
}
upDate();
} /* rePaint */
//Handling the dragging of the Mouse
/**
* mouseEntry detects when a mouse enters an area
* and detects if this corresponds to a dragging event...
*/
public void mouseEntry(connections target)
{
connections source;
if((dragged)&&(target.isMouseDroppedIn()))
{
int i=0;
source=null;
AFF(("dragging to "+target.theHost.machine));
while((i < vectConnections.size())&&(source==null)) /* A loop is done to find which connection has been dragged */
{
currentConnection=(connections) vectConnections.elementAt(i);
if((currentConnection.draggedOut)&&(currentConnection.connected))
{ /* if something has been dragged out of this connection and this connection is connected */
AFF(("dragging from "+currentConnection.theHost.machine));
source=currentConnection;
source.draggedOut=false;
fileXfer(source,target);
} /* if draggedOut */
i++;
} /* while i<size && source==null */
} /* if dragged */
dragged=false;
} /* mouseEntry */
/**
* fileXfer copies all the file selected in source to target.
* (in fact, just the kind of transfer needed is selected)
*/
public void fileXfer(connections source,connections target)
{
if(source.equals(target)==false)
{ /* no transfer in the same tree... */
/* first some operations are done to prepare the transfer */
target.goXferDir(); /* the target is asked to go in its transfer directory */
source.stackSelection(); /* the list of the file to be transfered is put in a stack */
/* a loop is done to deal with each copy separately */
while((source.stack).size()>0)
{
String fileName; /* the name of the files to be copied */
String sourcePath;
sourcePath=source.makePath((TreePath)source.stack.elementAt(0),true);
fileName=source.getFileName((TreePath)source.stack.elementAt(0));
AFF(("sourcePath "+sourcePath));
/* then the mode of transfer is selected */
if((source.theHost.machine.equals(LOCAL_MACHINE)))
{
if((target.theHost.machine.equals(LOCAL_MACHINE)))
{
doubleLocalXfer(source,target,sourcePath,fileName);
} /* local->local */
else
{
localRemoteXfer(source,target,sourcePath,fileName);
} /* local->remote */
}
else
{
if((target.theHost.machine.equals(LOCAL_MACHINE)))
{
remoteLocalXfer(source,target,sourcePath,fileName);
} /* remote->local */
else
{
doubleRemoteXfer(source,target,sourcePath,fileName);
} /* remote->remote */
}
source.stack.removeElementAt(0);
} /* while stack size > 0 */
target.ftp.setDir(target.ftp.currentTreePath);
} /* source != target */
} /* fileXfer */
/**
* doubleLocalXfer handles a file transfer between two local host
*/
public void doubleLocalXfer(connections source,connections target,String sourcePath,String fileName)
{
RandomAccessFile sourceFile;
RandomAccessFile targetFile;
boolean noError;
byte buffer[] = new byte[BUFFER_SIZE];
try /* let's try to open the file containing the source */
{
sourceFile = new RandomAccessFile(sourcePath,"r");
}
catch (IOException e)
{
sourceFile = null;
AFF((e.getMessage()));
}
catch (SecurityException e)
{
sourceFile = null;
AFF((e.getMessage()));
}
try /* let's try to open the file where goes the target */
{
targetFile = new RandomAccessFile(new File(target.ftp.currentPath,fileName),"rw");
}
catch (IOException e)
{
targetFile = null;
AFF((e.getMessage()));
}
catch (SecurityException e)
{
targetFile = null;
AFF((e.getMessage()));
}
noError=true;
while (noError)
{
int lengthRead=0;
try /* let's try to read the file*/
{
lengthRead=(sourceFile.read(buffer));
noError=(lengthRead!=-1); /* the line is read from the file */
/* the end of stream is reached if read returns -1 */
}
catch (EOFException e)
{
noError=false;
}
catch (IOException e)
{
AFF((e.getMessage()));
noError=false;
}
try /* let's try to read the file*/
{
targetFile.write(buffer,0,lengthRead);
}
catch (IOException e)
{
AFF((e.getMessage()));
noError=false;
}
buffer=new byte[BUFFER_SIZE];
} /* while noError */
try
{
sourceFile.close();
}
catch (IOException e)
{
AFF((e.getMessage()));
} /* catch close */
try
{
targetFile.close();
}
catch (IOException e)
{
AFF((e.getMessage()));
} /* catch close */
} /* doubleLocalXfer */
/**
* localRemoteXfer handles a file transfer from a local to a remote host
*/
public void localRemoteXfer(connections source,connections target,String sourcePath,String fileName)
{ /* we are sure that target is a FTP connection */
((module_ftp)target.ftp).sendFile(sourcePath,fileName);
} /* localRemoteXfer */
/**
* remoteLocalXfer handles a file transfer from a remote to a local host
*/
public void remoteLocalXfer(connections source,connections target,String sourcePath,String fileName)
{ /* we are sure that source is a FTP connection */
String thisPath=target.ftp.currentPath.concat(target.ftp.localPathSeparator);
if(!(thisPath.endsWith(target.ftp.localPathSeparator)))
{
thisPath=thisPath.concat(target.ftp.localPathSeparator);
}
((module_ftp)source.ftp).receiveFile(sourcePath,fileName,thisPath);
} /* remoteLocalXfer */
/**
* doubleRemoteXfer handles a file transfer between two remote host
*/
public void doubleRemoteXfer(connections source,connections target,String sourcePath,String fileName)
{ /* we are sure that both source and target are FTP connections */
String port; /* the port number on which the target listens */
AFF(("double Remote "));
port=((module_ftp)target.ftp).pasvRemote();
((module_ftp)source.ftp).sendRemote(port,sourcePath);
((module_ftp)target.ftp).receiveRemote(fileName);
((module_ftp)source.ftp).receive();
((module_ftp)target.ftp).receive();
} /* doubleRemoteXfer */
/**
* removeConnection removes a connection from the connection vector
*/
public void removeConnection(connections c)
{
int i=0;
while((i>=0)&&(i < vectConnections.size()))
{ /* a loop is done to find which connection is to be removed */
currentConnection=(connections) vectConnections.elementAt(i);
if(currentConnection.equals(c))
{
currentConnection.disconnect(); /* the connection is closed */
if (vectConnections.size()>1)
{ /* and then removed if it makes sens (ie there will be some connections left) */
vectConnections.removeElementAt(i);
}
i=-1; /* i is set to a negative value to terminate the loop */
}
else
{
i++;
}
}
repaint();
} /* removeConnection */
//The destructor
public void destroy()
{
AFF(("Debut du processus de deconnection"));
for (int i=0; i < vectConnections.size(); i++) /* a loop is done to close all connections */
{
currentConnection=(connections) vectConnections.elementAt(i);
currentConnection.disconnect();
}
AFF(("Au revoir"));
System.exit(0);
}
//main
public static void main(String args[])
{
NicoFTP Win = new NicoFTP();
}
}
#include "c:\disk_f\programmation\Java\FTP\textes.java"
import java.awt.*;
import host_list.*;
import com.sun.java.swing.*;
import com.sun.java.swing.tree.TreePath;
import com.sun.java.swing.tree.*;
import MListener.*;
//import MMotionListener.*;
import module_com.*;
import aHost.*;
import java.util.*;
import sizeableScrollPane.*;
import java.awt.event.*;
import toolBarActionListener.*;
/**
* The connections class contains all the elements used by each sub frame of the main window
*/
public class connections
{
int height;
int width;
/**
* urc_x and urc_y are the coordinates of the upper right corner
* of the display area of this connection
*/
int urc_x;
int urc_y;
/**
* this boolean knows if this connexions is currently connected or not
*/
boolean connected;
host_list hostRecords;
DISPLAY_TYPE displayArea;
/**
* The component that corresponds to the visual part of this connection eg: a ScrollPane
*/
Component connectVisuCompo;
/**
* The component that has the informative part of the connection: eg a JList
*/
Component connectListCompo;
In