You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by bo...@locus.apache.org on 2000/11/08 18:01:32 UTC

cvs commit: jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/net FTP.java TelnetTask.java

bodewig     00/11/08 09:01:22

  Modified:    .        build.xml
               src/main/org/apache/tools/ant/taskdefs defaults.properties
  Added:       src/main/org/apache/tools/ant/taskdefs/optional/net FTP.java
                        TelnetTask.java
  Removed:     src/main/org/apache/tools/ant/taskdefs/optional FTP.java
  Log:
  Added a new optional telnet task.
  
  Submitted by:	Scott Carlson <sc...@yahoo.com>
  
  Moved optional FTP task to the new net package.
  
  Revision  Changes    Path
  1.96      +2 -2      jakarta-ant/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/build.xml,v
  retrieving revision 1.95
  retrieving revision 1.96
  diff -u -r1.95 -r1.96
  --- build.xml	2000/11/07 20:42:48	1.95
  +++ build.xml	2000/11/08 17:00:07	1.96
  @@ -68,7 +68,7 @@
       <available property="ejb.DDCreator.present" classname="weblogic.ejb.utils.DDCreator" />
       <available property="ejb.wls.present" classname="weblogic.Server" />
       <available property="junit.present" classname="junit.framework.TestCase" />
  -    <available property="ftp.present" classname="com.oroinc.net.ftp.FTPClient" />
  +    <available property="netcomp.present" classname="com.oroinc.net.ftp.FTPClient" />
       <available property="starteam.present" classname="com.starbase.util.Platform" />
       <available property="antlr.present" classname="antlr.Tool" />
       <available property="vaj.present" classname="com.ibm.ivj.util.base.Workspace" />
  @@ -106,7 +106,7 @@
         <exclude name="**/EjbJar.java" unless="jdk1.2+" />
         <exclude name="**/*DeploymentTool.java" unless="jdk1.2+" />
         <exclude name="**/junit/*" unless="junit.present" />
  -      <exclude name="**/FTP*.java" unless="ftp.present" />
  +      <exclude name="**/net/*.java" unless="netcomp.present" />
         <exclude name="**/AntStarTeam*.java" unless="starteam.present" />
         <exclude name="**/ANTLR.java" unless="antlr.present" />
         <exclude name="**/ide/VAJ*.java" unless="vaj.present" />
  
  
  
  1.51      +2 -1      jakarta-ant/src/main/org/apache/tools/ant/taskdefs/defaults.properties
  
  Index: defaults.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/defaults.properties,v
  retrieving revision 1.50
  retrieving revision 1.51
  diff -u -r1.50 -r1.51
  --- defaults.properties	2000/11/07 20:31:00	1.50
  +++ defaults.properties	2000/11/08 17:00:25	1.51
  @@ -56,7 +56,7 @@
   mparse=org.apache.tools.ant.taskdefs.optional.metamata.MParse
   junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask
   cab=org.apache.tools.ant.taskdefs.optional.Cab
  -ftp=org.apache.tools.ant.taskdefs.optional.FTP
  +ftp=org.apache.tools.ant.taskdefs.optional.net.FTP
   javacc=org.apache.tools.ant.taskdefs.optional.javacc.JavaCC
   jjtree=org.apache.tools.ant.taskdefs.optional.javacc.JJTree
   starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut
  @@ -70,6 +70,7 @@
   vajload=org.apache.tools.ant.taskdefs.optional.ide.VAJLoadProjects
   vajexport=org.apache.tools.ant.taskdefs.optional.ide.VAJExport
   vajimport=org.apache.tools.ant.taskdefs.optional.ide.VAJImport
  +telnet=org.apache.tools.ant.taskdefs.optional.net.TelnetTask
   
   # deprecated ant tasks (kept for back compatibility)
   javadoc2=org.apache.tools.ant.taskdefs.Javadoc
  
  
  
  1.1                  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/net/FTP.java
  
  Index: FTP.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.tools.ant.taskdefs.optional.net;
  
  import org.apache.tools.ant.*;
  import org.apache.tools.ant.types.*;
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import com.oroinc.net.ftp.*;
  
  /**
   * Basic FTP client that performs the following actions:
   * <ul>
   *   <li><strong>send</strong> - send files to a remote server.  This is the
   *              default action.</li>
   *   <li><strong>get</strong> - retrive files from a remote server.</li>
   *   <li><strong>del</strong> - delete files from a remote server.</li>
   *   <li><strong>list</strong> - create a file listing.</li>
   * </ul>
   *
   * @author Roger Vaughn <a href="mailto:rvaughn@seaconinc.com">rvaughn@seaconinc.com</a>
   * @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com</a>
   */
  public class FTP
      extends Task
  {
      protected final static int SEND_FILES   = 0;
      protected final static int GET_FILES    = 1;
      protected final static int DEL_FILES    = 2;	
      protected final static int LIST_FILES   = 3;
      
      private String remotedir;
      private String server;
      private String userid;
      private String password;
      private File listing;
      private boolean binary = true;
      private boolean verbose = false;
      private boolean newerOnly = false;
      private int action = SEND_FILES;
      private Vector filesets = new Vector();
      private Vector dirCache = new Vector();
      private int transferred = 0;
      private String remoteFileSep = "/";
      private int port = 21;
  
      protected final static String[] ACTION_STRS = {
          "sending",
          "getting",
          "deleting",
          "listing"
      };
  
      protected final static String[] COMPLETED_ACTION_STRS = {
          "sent",
          "retrieved",
          "deleted",
          "listed"
      };		
  	
      protected class FTPDirectoryScanner extends DirectoryScanner {
          protected FTPClient ftp = null;
  	
          public FTPDirectoryScanner(FTPClient ftp) {
              super();
              this.ftp = ftp;
          }
  
          public void scan() {
              if (includes == null) {
                  // No includes supplied, so set it to 'matches all'
                  includes = new String[1];
                  includes[0] = "**";
              }
              if (excludes == null) {
                  excludes = new String[0];
              }
  
              filesIncluded = new Vector();
              filesNotIncluded = new Vector();
              filesExcluded = new Vector();
              dirsIncluded = new Vector();
              dirsNotIncluded = new Vector();
              dirsExcluded = new Vector();
  
              try {
                  String cwd = ftp.printWorkingDirectory();
                  scandir(".", "", true); // always start from the current ftp working dir
                  ftp.changeWorkingDirectory(cwd);
              } catch (IOException e) {
                  throw new BuildException("Unable to scan FTP server: ", e);
              }
          }
  
          protected void scandir(String dir, String vpath, boolean fast) {
              try {
                  if (!ftp.changeWorkingDirectory(dir)) {
                      return;
                  }
  
                  FTPFile[] newfiles = ftp.listFiles();
                  if (newfiles == null) {
                      return;    // no files in directory.
                  }
  
                  for (int i = 0; i < newfiles.length; i++) {
                      FTPFile file = newfiles[i];
                      String name = vpath + file.getName();
                      if (file.isDirectory()) {
                          if (isIncluded(name)) {
                              if (!isExcluded(name)) {
                                  dirsIncluded.addElement(name);
                                  if (fast) {
                                      scandir(name, name + File.separator, fast);
                                  }
                              } else {
                                  dirsExcluded.addElement(name);
                              }
                          } else {
                              dirsNotIncluded.addElement(name);
                              if (fast && couldHoldIncluded(name)) {
                                  scandir(name, name + File.separator, fast);
                              }
                          }
                          if (!fast) {
                              scandir(name, name + File.separator, fast);
                          }
                      } else {
                          if (file.isFile()) {
                              if (isIncluded(name)) {
                                  if (!isExcluded(name)) {
                                      filesIncluded.addElement(name);
                                  } else {
                                      filesExcluded.addElement(name);
                                  }
                              } else {
                                  filesNotIncluded.addElement(name);
                              }
                          }
                      }
                  }
              } catch (IOException e) {
                  throw new BuildException("Error while communicating with FTP server: ", e);
              }
          }
      }	
  
      /**
       * Sets the remote directory where files will be placed.  This may
       * be a relative or absolute path, and must be in the path syntax
       * expected by the remote server.  No correction of path syntax will
       * be performed.
       */
      public void setRemotedir(String dir)
      {
          this.remotedir = dir;
      }
  
      /**
       * Sets the FTP server to send files to.
       */
      public void setServer(String server)
      {
          this.server = server;
      }
  
      /**
       * Sets the FTP port used by the remote server.
       */
      public void setPort(int port)
      {
          this.port = port;
      }
  
      /**
       * Sets the login user id to use on the specified server.
       */
      public void setUserid(String userid)
      {
          this.userid = userid;
      }
  
      /**
       * Sets the login password for the given user id.
       */
      public void setPassword(String password)
      {
          this.password = password;
      }
  
      /**
       * Specifies whether to use binary-mode or text-mode transfers.  Set
       * to true to send binary mode.  Binary mode is enabled by default.
       */
      public void setBinary(boolean binary)
      {
          this.binary = binary;
      }
  
      /**
       * Set to true to receive notification about each file as it is
       * transferred.
       */
      public void setVerbose(boolean verbose)
      {
          this.verbose = verbose;
      }
  
      /**
       * Set to true to transmit only files that are new or changed from their
       * remote counterparts.  The default is to transmit all files.
       */
      public void setNewer(boolean newer)
      {
          this.newerOnly = newer;
      }
  
      /**
       * A synonym for setNewer.  Set to true to transmit only new or changed
       * files.
       */
      public void setDepends(boolean depends)
      {
          this.newerOnly = depends;
      }
  
      /**
       * Sets the remote file separator character.  This normally defaults to
       * the Unix standard forward slash, but can be manually overridden using
       * this call if the remote server requires some other separator.  Only
       * the first character of the string is used.
       */
      public void setSeparator(String separator)
      {
          remoteFileSep = separator;
      }
  
      /**
       * Adds a set of files (nested fileset attribute).
       */
      public void addFileset(FileSet set) {
          filesets.addElement(set);
      }
  
      /**
       * Sets the FTP action to be taken.  Currently accepts "put", "get",
       * "del", and "list".
       */
      public void setAction(String action) throws BuildException
      {
          if (action.toLowerCase().equals("send") ||
              action.toLowerCase().equals("put"))
          {
              this.action = SEND_FILES;
          }
          else if (action.toLowerCase().equals("recv") ||
                   action.toLowerCase().equals("get"))
          {
              this.action = GET_FILES;
          }
          else if (action.toLowerCase().equals("del") ||
                   action.toLowerCase().equals("delete" ))
          {
              this.action = DEL_FILES;
          }
          else if (action.toLowerCase().equals("list"))
          {
              this.action = LIST_FILES;
          }
          else
          {
              throw new BuildException("action " + action + " is not supported");
          }
      }
      
      /**
       * The output file for the "list" action.  This attribute is ignored for
       * any other actions.
       */
      public void setListing(File listing) throws BuildException {
          this.listing = listing;
      }	
      
  
      /**
       * Checks to see that all required parameters are set.
       */
      protected void checkConfiguration() throws BuildException
      {
          if (server == null)
          {
              throw new BuildException("server attribute must be set!");
          }
          if (userid == null)
          {
              throw new BuildException("userid attribute must be set!");
          }
          if (password == null)
          {
              throw new BuildException("password attribute must be set!");
          }
          
          if ((action == LIST_FILES) && (listing == null))
          {
              throw new BuildException("listing attribute must be set for list action!");
          }
      }
  
      /**
       * For each file in the fileset, do the appropriate action: send, get, delete,
       * or list.
       */
      protected int transferFiles(FTPClient ftp, FileSet fs)
          throws IOException, BuildException
      {
          FileScanner ds;
  
          if (action == SEND_FILES) {
              ds = fs.getDirectoryScanner(project);
          } else {
              ds = new FTPDirectoryScanner(ftp);
              fs.setupDirectoryScanner(ds, project);
              ds.scan();
          }			
  				
          String[] dsfiles = ds.getIncludedFiles();
          String dir = null;
          if ((ds.getBasedir() == null) && ((action == SEND_FILES) || (action == GET_FILES))) {
              throw new BuildException( "the dir attribute must be set for send and get actions" );
          } else {
              if ((action == SEND_FILES) || (action == GET_FILES)) {
                  dir = ds.getBasedir().getAbsolutePath();
              }
          }
  
          // If we are doing a listing, we need the output stream created now.
          BufferedWriter bw = null;
          if (action == LIST_FILES) {
              File pd = new File(listing.getParent());
              if (!pd.exists()) {
                  pd.mkdirs();
              }
              bw = new BufferedWriter(new FileWriter(listing));
          }
  
          for (int i = 0; i < dsfiles.length; i++)
          {
              switch (action) {
                  case SEND_FILES: {
                      sendFile(ftp, dir, dsfiles[i]);
                      break;
                  }
  
                  case GET_FILES: {
                      getFile(ftp, dir, dsfiles[i]);
                      break;
                  }
  
                  case DEL_FILES: {
                      delFile(ftp, dsfiles[i]);
                      break;
                  }
  
                  case LIST_FILES: {
                      listFile(ftp, bw, dsfiles[i]);
                      break;
                  }
  
                  default: {
                      throw new BuildException("unknown ftp action " + action );
                  }
              }
          }
  
          if (action == LIST_FILES) {
              bw.close();
          }
  
          return dsfiles.length;
      }
  
      /**
       * Sends all files specified by the configured filesets to the remote
       * server.
       */
      protected void transferFiles(FTPClient ftp)
          throws IOException, BuildException
      {
          transferred = 0;
          
          if (filesets.size() == 0)
          {
              throw new BuildException("at least one fileset must be specified.");
          }
          else
          {
              // get files from filesets
              for (int i = 0; i < filesets.size(); i++)
              {
                  FileSet fs = (FileSet) filesets.elementAt(i);
                  if (fs != null)
                  {
                      transferFiles(ftp, fs);
                  }
              }
          }
  
          log(transferred + " files " + COMPLETED_ACTION_STRS[action]);
      }
  
      /**
       * Correct a file path to correspond to the remote host requirements.
       * This implementation currently assumes that the remote end can
       * handle Unix-style paths with forward-slash separators.  This can
       * be overridden with the <code>separator</code> task parameter.  No
       * attempt is made to determine what syntax is appropriate for the
       * remote host.
       */
      protected String resolveFile(String file)
      {
          return file.replace(System.getProperty("file.separator").charAt(0),
                              remoteFileSep.charAt(0));
      }
  
      /**
       * Creates all parent directories specified in a complete relative
       * pathname.  Attempts to create existing directories will not cause
       * errors.
       */
      protected void createParents(FTPClient ftp, String filename)
          throws IOException, BuildException
      {
          Vector parents = new Vector();
          File dir = new File(filename);
          String dirname;
  
          while ((dirname = dir.getParent()) != null)
          {
              dir = new File(dirname);
              parents.addElement(dir);
          }
  
          for (int i = parents.size() - 1; i >= 0; i--)
          {
              dir = (File)parents.elementAt(i);
              if (!dirCache.contains(dir))
              {
                  log("creating remote directory " + resolveFile(dir.getPath()),
                      Project.MSG_VERBOSE);
                  ftp.makeDirectory(resolveFile(dir.getPath()));
                  if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()) &&
                      (ftp.getReplyCode() != 550))
                  {
                      throw new BuildException(
                          "could not create directory: " +
                          ftp.getReplyString());
                  }
                  dirCache.addElement(dir);
              }
          }
      }
  
      /**
       * Checks to see if the remote file is current as compared with the
       * local file.  Returns true if the remote file is up to date.
       */
      protected boolean isUpToDate(FTPClient ftp, File localFile, String remoteFile)
          throws IOException, BuildException
      {
          log("checking date for " + remoteFile, Project.MSG_VERBOSE);
          
          FTPFile[] files = ftp.listFiles(remoteFile);
          if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
          {
              throw new BuildException(
                  "could not date test remote file: " +
                  ftp.getReplyString());
          }
  
          if (files == null)
          {
              return false;
          }
  
          long remoteTimestamp = files[0].getTimestamp().getTime().getTime();
          long localTimestamp = localFile.lastModified();
          if (this.action == SEND_FILES) {
              return remoteTimestamp > localTimestamp;
          } else {
              return localTimestamp > remoteTimestamp;
          }
      }
  
      /**
       * Sends a single file to the remote host.
       * <code>filename</code> may contain a relative path specification.
       * When this is the case, <code>sendFile</code> will attempt to create
       * any necessary parent directories before sending the file.  The file
       * will then be sent using the entire relative path spec - no attempt
       * is made to change directories.  It is anticipated that this may
       * eventually cause problems with some FTP servers, but it simplifies
       * the coding.
       */
      protected void sendFile(FTPClient ftp, String dir, String filename)
          throws IOException, BuildException
      {
          InputStream instream = null;
          try
          {
              File file = project.resolveFile(new File(dir, filename).getPath());
  
              if (newerOnly && isUpToDate(ftp, file, resolveFile(filename)))
                  return;
  
              if (verbose)
              {
                  log("transferring " + file.getAbsolutePath());
              }
              
              instream = new BufferedInputStream(new FileInputStream(file));
              
              createParents(ftp, filename);
              
              ftp.storeFile(resolveFile(filename), instream);
              
              if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
              {
                  throw new BuildException(
                      "could not transfer file: " +
                      ftp.getReplyString());
              }
              
              log("File " + file.getAbsolutePath() + " copied to " + server,
                  Project.MSG_VERBOSE);
  
              transferred++;
          }
          finally
          {            
              if (instream != null)
              {
                  try
                  {
                      instream.close();
                  }
                  catch(IOException ex)
                  {
                      // ignore it
                  }
              }
          }
      }
  
      /**
       * Delete a file from the remote host.
       */
      protected void delFile(FTPClient ftp, String filename)
              throws IOException, BuildException {
          if (verbose) {
              log("deleting " + filename);
          }
  
          if (!ftp.deleteFile(resolveFile(filename))) {
              throw new BuildException("could not delete file: " + ftp.getReplyString());
          }
  
          log("File " + filename + " deleted from " + server, Project.MSG_VERBOSE); 
  
          transferred++;
      }
  
      /**
       * Retrieve a single file to the remote host.
       * <code>filename</code> may contain a relative path specification.
       * The file will then be retreived using the entire relative path spec - 
       * no attempt is made to change directories.  It is anticipated that this may
       * eventually cause problems with some FTP servers, but it simplifies
       * the coding.
       */
      protected void getFile(FTPClient ftp, String dir, String filename)
          throws IOException, BuildException
      {
          OutputStream outstream = null;
          try
          {
              File file = project.resolveFile(new File(dir, filename).getPath());
  
              if (newerOnly && isUpToDate(ftp, file, resolveFile(filename)))
                  return;
  
              if (verbose)
              {
                  log("transferring " + filename + " to " + file.getAbsolutePath());
              }
  
  			
              File pdir = new File(file.getParent());	// stay 1.1 compatible
              if (!pdir.exists()) {
                  pdir.mkdirs();
              }		
              outstream = new BufferedOutputStream(new FileOutputStream(file));
              ftp.retrieveFile(resolveFile(filename), outstream);
  			
              if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
              {
                  throw new BuildException(
  "could not transfer file: " +
   ftp.getReplyString());
              }
  			
              log("File " + file.getAbsolutePath() + " copied from " + server,
   Project.MSG_VERBOSE);
  
              transferred++;
          }
          finally
          {            
              if (outstream != null)
              {
                  try
                  {
                      outstream.close();
                  }
                  catch(IOException ex)
                  {
                      // ignore it
                  }
              }
          }
      }
  
      /**
       * List information about a single file from the remote host.
       * <code>filename</code> may contain a relative path specification.
       * The file listing will then be retrieved using the entire relative path spec 
       * - no attempt is made to change directories.  It is anticipated that this may
       * eventually cause problems with some FTP servers, but it simplifies
       * the coding.
       */
      protected void listFile(FTPClient ftp, BufferedWriter bw, String filename)
          throws IOException, BuildException 
      {
          if (verbose) {
              log("listing " + filename);
          }
  
          FTPFile ftpfile = ftp.listFiles(resolveFile(filename))[0];
          bw.write(ftpfile.toString());
          bw.newLine();
  
          transferred++;
      }
  
      /**
       * Runs the task.
       */
      public void execute()
          throws BuildException
      {
          checkConfiguration();
          
          FTPClient ftp = null;
  
          try
          {
              log("Opening FTP connection to " + server, Project.MSG_VERBOSE);
  
              ftp = new FTPClient();
              
              ftp.connect(server, port);
              if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
              {
                  throw new BuildException("FTP connection failed: " + ftp.getReplyString());
              }
  
              log("connected", Project.MSG_VERBOSE);
              log("logging in to FTP server", Project.MSG_VERBOSE);
  
              if (!ftp.login(userid, password))
              {
                  throw new BuildException("Could not login to FTP server");
              }
  
              log("login succeeded", Project.MSG_VERBOSE);
              
              if (binary)
              {
                  ftp.setFileType(com.oroinc.net.ftp.FTP.IMAGE_FILE_TYPE);
                  if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
                  {
                      throw new BuildException(
                          "could not set transfer type: " +
                          ftp.getReplyString());
                  }
              }
  
              if (remotedir != null)
              {
                  log("changing the remote directory", Project.MSG_VERBOSE);
                  ftp.changeWorkingDirectory(remotedir);
                  if (!FTPReply.isPositiveCompletion(ftp.getReplyCode()))
                  {
                      throw new BuildException(
                          "could not change remote directory: " +
                          ftp.getReplyString());
                  }
              }
  
              log(ACTION_STRS[action] + " files");
              transferFiles(ftp);
  
          }
          catch(IOException ex)
          {
              throw new BuildException("error during FTP transfer: " + ex);
          }
          finally
          {
              /*
              if (ftp != null && ftp.isConnected())
              {
                  try
                  {
                      // this hangs - I don't know why.
                      ftp.disconnect();
                  }
                  catch(IOException ex)
                  {
                      // ignore it
                  }
              }
              */
          }
      }
  }
  
  
  
  1.1                  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java
  
  Index: TelnetTask.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.tools.ant.taskdefs.optional.net;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.Task;
  import org.apache.tools.ant.Project;
  import org.apache.tools.ant.DirectoryScanner;
  import org.apache.tools.ant.taskdefs.MatchingTask;
  import com.oroinc.net.telnet.*;
  import org.apache.tools.ant.BuildException;
  import java.io.*;
  import java.lang.*;
  import java.util.*;
  
  /**
   * Class to provide automated telnet protocol support for the Ant build tool
   *
   * @author Scott Carlson<a href="mailto:ScottCarlson@email.com">ScottCarlson@email.com</a>
   * @version $Revision: 1.1 $
   */
  
  public class TelnetTask extends Task {
      /**
       *  The userid to login with, if automated login is used
       */
      private String userid  = null;
  
      /**
       *  The password to login with, if automated login is used
       */
      private String password= null;
  
      /**
       *  The server to connect to. 
       */
      private String server  = null;
  
      /**
       *  The tcp port to connect to. 
       */
      private int port = 23;
  
      /**
       *  The Object which handles the telnet session.
       */
      private AntTelnetClient telnet = null;
  
      /**
       *  The list of read/write commands for this session
       */
      private Vector telnetTasks = new Vector();
  
      /** 
       *  Verify that all parameters are included. 
       *  Connect and possibly login
       *  Iterate through the list of Reads and writes 
       */
      public void execute() throws BuildException 
      {
         /**  A server name is required to continue */
         if (server== null)
             throw new BuildException("No Server Specified");
         /**  A userid and password must appear together 
          *   if they appear.  They are not required.
          */
         if (userid == null && password != null)
             throw new BuildException("No Userid Specified");
         if (password == null && userid != null)
             throw new BuildException("No Password Specified");
  
         /**  Create the telnet client object */
         telnet = new AntTelnetClient();
         try {
             telnet.connect(server, port);
         } catch(IOException e) {
             throw new BuildException("Can't connect to "+server);
         }
         /**  Login if userid and password were specified */
         if (userid != null && password != null)
            login();
         /**  Process each sub command */
         Enumeration tasksToRun = telnetTasks.elements();
         while (tasksToRun!=null && tasksToRun.hasMoreElements())
         {
             TelnetSubTask task = (TelnetSubTask) tasksToRun.nextElement();
             task.execute(telnet);
         }
      }
  
      /**  
       *  Process a 'typical' login.  If it differs, use the read 
       *  and write tasks explicitely
       */
      private void login()
      {
         telnet.waitForString("ogin:");
         telnet.sendString(userid);
         telnet.waitForString("assword:");
         telnet.sendString(password);
      }
  
      /**
       *  Set the userid attribute 
       */
      public void setUserid(String u) { this.userid = u; }
      /**
       *  Set the password attribute 
       */
      public void setPassword(String p) { this.password = p; }
      /**
       *  Set the server address attribute 
       */
      public void setServer(String m) { this.server = m; }
      /**
       *  Set the tcp port to connect to attribute 
       */
      public void setPort(int p) { this.port = p; }
  
      /**
       *  A subTask <read> tag was found.  Create the object, 
       *  Save it in our list, and return it.
       */
     
      public TelnetSubTask createRead()
      {
          TelnetSubTask task = (TelnetSubTask)new TelnetRead();
          telnetTasks.addElement(task);
          return task;
      }
  
      /**
       *  A subTask <write> tag was found.  Create the object, 
       *  Save it in our list, and return it.
       */
      public TelnetSubTask createWrite()
      {
          TelnetSubTask task = (TelnetSubTask)new TelnetWrite();
          telnetTasks.addElement(task);
          return task;
      }
  
      /**  
       *  This class is the parent of the Read and Write tasks.
       *  It handles the common attributes for both.
       */
      public class TelnetSubTask
      {
          protected String taskString= "";
          public void execute(AntTelnetClient telnet) 
                  throws BuildException
          {
              throw new BuildException("Shouldn't be able instantiate a SubTask directly");
          }
          public void addText(String s) { setString(s);}
          public void setString(String s)
          {
             taskString += s; 
          }
      }
      /**
       *  This class sends text to the connected server 
       */
      public class TelnetWrite extends TelnetSubTask
      {
          public void execute(AntTelnetClient telnet) 
                 throws BuildException
          {
              telnet.sendString(taskString);
          }
      }
      /**
       *  This class reads the output from the connected server
       *  until the required string is found. 
       */
      public class TelnetRead extends TelnetSubTask
      {
          public void execute(AntTelnetClient telnet) 
                 throws BuildException
          {
              telnet.waitForString(taskString);
          }
      }
      /**
       *  This class handles the abstraction of the telnet protocol.
       *  Currently it is a wrapper around <a href="www.oroinc.com">ORO</a>'s 
       *  NetComponents
       */
      public class AntTelnetClient extends TelnetClient
      {
        public void waitForString(String s)
        {
          InputStream is =this.getInputStream();
          try {
            StringBuffer sb = new StringBuffer();
            while (sb.toString().indexOf(s) == -1)
            {
                while (is.available() == 0);
                int iC = is.read();
                Character c = new Character((char)iC);
                sb.append(c);
            }
            log(sb.toString(), Project.MSG_INFO);
          } catch (Exception e)
          { 
              throw new BuildException(e, getLocation());
          }
        }
      
        public void sendString(String s)
        {
          OutputStream os =this.getOutputStream();
          try {
            os.write((s + "\n").getBytes());
            log(s, Project.MSG_INFO);
            os.flush();
          } catch (Exception e)
          { 
            throw new BuildException(e, getLocation());
          }
        }
      }
  }