001/*
002 * Version 0.70 01/04/2002
003 *
004 * Visit my url for update: http://www.geocities.com/beapetrovicova/
005 * 
006 * jFtp was developed by Bea Petrovicova <beapetrovicova@yahoo.com>.
007 * The design and implementation of jFtp are available for royalty-free 
008 * adoption and use. This software is provided 'as is' without any 
009 * guarantees. Copyright is retained by Bea Petrovicova. Redistribution 
010 * of any part of jFtp or any derivative works must include this notice.
011 * 
012 */  
013
014package cz.dhl.ftp;
015
016import cz.dhl.io.CoSource;
017import java.io.IOException;
018
019/**
020 * Allows connect to FTP server and 
021 * maintains control connection.
022 * 
023 * @Version 0.70 01/04/2002
024 * @author Bea Petrovicova <beapetrovicova@yahoo.com>  
025 */
026public final class Ftp implements CoSource
027{
028   /** Default FTP port number. */
029   public static final int PORT = 21;
030
031   private FtpContext context = new FtpContext();
032   FtpControlSocket control = new FtpControlSocket(context);
033
034   /** Creates a new Ftp instance. */
035   public Ftp() {}
036   
037   /** Connect & login.
038    * @param connect Connection details.
039    * @return port Server FTP port number normally 21. */
040   public boolean connect(FtpConnect connect) throws IOException
041   {  if(connect(connect.getHostName(),connect.getPortNum()))
042         if(login(connect.getUserName(),connect.getPassWord()))
043         { String pathname = connect.getPathName();
044           if(connect.getPathName().length() > 0)
045               cd(connect.getPathName());
046         } else disconnect();
047      return isConnected();
048   }   
049   
050   /** Connect to server, open control connection.
051    * @param server Server DNS server name or dot delimited IP address.
052    * @return port Server FTP port number normally 21. */
053   public boolean connect(String server,int port) throws IOException
054   {  if(!isConnected() && server!=null)
055      {  if(control.connect(server, port))
056         {  if(!control.completeCommand(FtpInterpret.getReplies("login-done")))
057            {  printlog("< Can't obtain welcome message from host! >"); 
058                  control.disconnect(); return false;            
059            } else return true;
060         } else return false;
061      } else return false;
062   }
063
064   /** Disconnect from server, close control connection. */
065   public void disconnect()
066      { control.disconnect(); }
067
068   /** Abort connection. */
069   public void abort()
070   {  //context.setConsole(null); 
071      disconnect();
072   }  
073   
074   /** Log in to server, enter username and password.
075    * <P><B>USER</B> - user name.</P>
076    * <P>The argument field is a Telnet string identifying the 
077    * user. The user identification is that does require the 
078    * server for access to its file system. This command will 
079    * normally be the first command transmitted by the user after 
080    * the control connections are made (some servers may require 
081    * this). Additional identification information in the form of 
082    * a password and/or an account command may also be required 
083    * by some servers. Servers may allow a new USER command to 
084    * be entered at any point in order to change the access 
085    * control and/or accounting information. This has the effect 
086    * of flushing any user, password, and account information 
087    * already supplied and beginning the login sequence again. 
088    * All transfer parameters are unchanged and any file transfer 
089    * in progress is completed under the old access control 
090    * parameters.</P>
091    * <P><B>PASS</B> - password.</P>
092    * <P>The argument field is a Telnet string specifying the user's 
093    * password. This command must be immediately preceded by the 
094    * user name command, and, for some sites, completes the 
095    * user's identification for access control. Since password 
096    * information is quite sensitive, it is desirable in general 
097    * to "mask" it or suppress typeout. It appears that the 
098    * server has no foolproof way to achieve this. It is 
099    * therefore the responsibility of the user-FTP process to 
100    * hide the sensitive password information.</P>
101    * @param username Server account username.
102    * @param password Server account password.
103    * @return True on success. */
104   public boolean login(String username,String password) throws IOException
105   {  if(control.executeCommand("USER " + username))
106         if(control.executeCommand("PASS " + password))
107            { syst(); return true; }
108         else { printlog("< Can't login to host. >"); return false; } 
109      else { printlog("< Can't login to host. >"); return false; }
110   }
111   
112   /** Returns server host name.
113    * @return Server host name on success. */
114   public String host() throws IOException
115   {  if(isConnected())
116         return control.server;
117      else throw new IOException("Ctrl: No Connection!"); 
118   }
119
120   /** Enter custom server command.
121    * <P>Not all FTP commands are accepted. 
122    * Exceptions are especially commands for transferring 
123    * files and altering way data transfer is performed.</P>
124    * @return True on success. */
125   public boolean command(String commandline) 
126      { return control.manualCommand(commandline); }
127   
128   /** Remove server directory.
129    * <P><B>RMD</B> - remove directory.</P>
130    * <P>This command causes the directory specified in the pathname 
131    * to be removed as a directory (if the pathname is absolute) 
132    * or as a subdirectory of the current working directory (if 
133    * the pathname is relative).</P>
134    * @param directory Name of directory to be removed.
135    * @return True on success. */
136   public boolean rmdir(String directory) 
137      { return control.executeCommand("RMD " + directory); }
138
139   /** Make server working directory.
140    * <P><B>MKD</B> - make directory.</P>
141    * <P>This command causes the directory specified in the 
142    * pathname to be created as a directory (if the pathname is 
143    * absolute) or as a subdirectory of the current working 
144    * directory (if the pathname is relative).</P>
145    * @param directory Name of newly created directory.
146    * @return True on success. */
147   public boolean mkdir(String directory) 
148      { return control.executeCommand("MKD " + directory); }
149   
150   /** Print server working directory.
151    * <P><B>PWD</B> - print working directory.</P>
152    * <P>This command causes the name of the current working 
153    * directory to be returned in the reply.</P>
154    * @return Current working directory. */
155   public String pwd() throws IOException
156   {  if(isConnected())
157      {  String directory = null, replyline;
158         control.executeCommand("PWD"); 
159         replyline = control.replyOfCommand();
160         try
161         {  directory = replyline.substring(
162            replyline.indexOf('\"')+1,replyline.lastIndexOf('\"')); }
163         catch (StringIndexOutOfBoundsException e)
164         {  throw new IOException("Ctrl: PWD, Invalid Format!"); }
165         return directory; 
166      } else throw new IOException("Ctrl: PWD, No Connection!"); 
167   }
168
169   /** Print server system.
170    * <P><B>SYST</B> - print server system.</P>
171    * <P>This command causes the name name and version of 
172    * the server system to be returned in the reply.</P>
173    * @return Server system. */
174   public String syst() throws IOException
175   {  if(isConnected())
176      {  control.executeCommand("SYST"); 
177         String system = control.replyOfCommand();
178         getContext().setServerSystemMode(FtpSetting.UNIX);
179         if(system!=null && system.toUpperCase().indexOf("WINDOWS") >=0)
180         {  getContext().setServerSystemMode(FtpSetting.WIN);
181            printlog("< File: Setting 'WIN' Server Mode >"); }
182         return system; 
183      } else throw new IOException("Ctrl: PWD, No Connection!"); 
184   }
185
186   /** Change server working directory.
187    * <P><B>CWD</B> - change working directory.</P>
188    * <P>This command allows the user to work with a different 
189    * directory or dataset for file storage or retrieval without 
190    * altering his login or accounting information. Transfer 
191    * parameters are similarly unchanged. The argument is a 
192    * pathname specifying a directory or other system dependent 
193    * file group designator.</P>
194    * @param directory Name of new working directory.</P>
195    * @return True on success. */
196   public boolean cd(String directory) 
197      { return control.executeCommand("CWD " + directory); }
198
199   /** Change server directory to parent.
200    * <P><B>CDUP</B> - change up.</P>
201    * <P>This command is a special case of CWD, and is included to 
202    * simplify the implementation of programs for transferring 
203    * directory trees between operating systems having different 
204    * File Transfer Protocol syntaxes for naming the parent 
205    * directory.</P>
206    * @return True on success. */
207   public boolean cdup() 
208      { return control.executeCommand("CDUP"); }
209
210   /** Delete server file.
211    * <P><B>DELE</B> - delete.</P>
212    * <P>This command causes the file specified in the pathname 
213    * to be deleted at the server site. If an extra level of 
214    * protection is desired (such as the query, "Do you really 
215    * wish to delete?"), it should be provided by the user-FTP 
216    * process.</P>
217    * @param filename Name of file to be deleted.
218    * @return True on success. */
219   public boolean rm(String filename) 
220      { return control.executeCommand("DELE " + filename); }
221
222   /** Rename server file.
223    * <P><B>RNFR</B> - rename from.</P>
224    * <P>This command specifies the old pathname of the file, 
225    * which is to be renamed. This command must be immediately 
226    * followed by a "rename to" command specifying the new file 
227    * pathname.</P>
228    * <P><B>RNTO</B> - rename to.</P>
229    * <P>This command specifies the new pathname of the file 
230    * specified in the immediately preceding "rename from" 
231    * command. Together the two commands cause a file to be 
232    * renamed.</P>
233    * @param oldfilename Old name of file.
234    * @param newfilename New name of file.
235    * @return True on success. */
236   public boolean mv(String oldfilename, String newfilename)
237   {  if(control.executeCommand("RNFR " + oldfilename))
238         return control.executeCommand("RNTO " + newfilename);
239      else return false;
240   } 
241   
242   /** Change server file mode.
243    * @param filename Name of file to change mode.
244    * @param mode Mode is UNIX "777" format string.
245    * @return True on success. */
246   public boolean chmod(String filename, String mode)
247      { return control.executeCommand("SITE CHMOD " + mode + " " + filename); }
248
249   /** Tests connection. */
250   public boolean isConnected() 
251      { return control.isConnected(); }
252 
253   /** Return FtpContext object.
254    * @return context
255    * @see cz.dhl.ftp.FtpContext */
256   public FtpContext getContext() { return context; }
257   
258   /* Print message line to output console. */
259   void printlog(String message) { context.printlog(message); }
260
261   /* Print object to standard output. */
262   void printerr(Exception exception) { context.printerr(exception); }
263};