I've just put together a task for issuing single remote commands on a telnet 
host.  Despite it's rough edges it's very useful to me, so it may be useful to 
someone else.  Please feel free to incorporate it in Ant or use it as you see 
fit.  It relies on NetComponents.

The task is called "Telnet"

I've built it in as a standard Task.

Here's an example of its attributes:
        <telnet host="telnet.host.com" user="anonymous" password="[EMAIL 
PROTECTED]"
                prompt="% " command="touch ihavebeenhere" />

It relies heavily on the user entering the correct prompt.

There are various problems with the Task:
- It waits endlessly for responses, so if something goes wrong it will just 
wait forever - I haven't got round to including a timeout.
- It assumes that the command prompt will not be issued as part of any other 
output between entering the password and giving the prompt.  Hence you want to 
enter as long a portion of the prompt as possible.
- It doesn't detect to see whether the command completed successfully - though 
it does at least display the response.
- It relies on a remote shell which understands ";" as a command delimiter and 
"echo" as a command line echo command.

... and probably lots of other things.

On the positive side, it gives a fair amount of helpful feedback.

Stuart.


Here's the patch to defaults.properties if you want to enter it as a default 
task:

Index: src/main/org/apache/tools/ant/taskdefs/defaults.properties
===================================================================
RCS file: 
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/defaults.properties,v
retrieving revision 1.47
diff -u -r1.47 defaults.properties
--- src/main/org/apache/tools/ant/taskdefs/defaults.properties  2000/10/25 
11:59:47     1.47
+++ src/main/org/apache/tools/ant/taskdefs/defaults.properties  2000/10/25 
23:12:09
@@ -42,6 +42,7 @@
 fail=org.apache.tools.ant.taskdefs.Exit
 war=org.apache.tools.ant.taskdefs.War
 uptodate=org.apache.tools.ant.taskdefs.UpToDate
+telnet=org.apache.tools.ant.taskdefs.Telnet
 
 # optional tasks
 script=org.apache.tools.ant.taskdefs.optional.Script


Here's the listing of the new task which should be filed as 
"src/main/org/apache/tools/ant/taskdefs/Telnet.java".  Sorry this isn't a patch 
because I could see how to create a patch for something that isn't already in 
the repository.  If anyone can tell me how I would be obliged.


/*
 * 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 [EMAIL PROTECTED]
 *
 * 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;

import com.oroinc.io.*;
import com.oroinc.net.telnet.*;
import java.io.*;
import java.net.*;
import java.util.*;
import org.apache.tools.ant.*;
import org.apache.tools.ant.types.*;

/**
 * <p>Task to allow remote commands to be issue on a telnet host.</p>
 *
 * <p>Example of task use:</p>
 * <code>&lt;telnet host="telnet.host.com" user="anonymous" password="[EMAIL 
PROTECTED]" prompt="% " command="touch ihavebeenhere" /&gt;</code> 
 *
 * @author Stuart Roebuck <a href="mailto:[EMAIL PROTECTED]">[EMAIL 
PROTECTED]</a>
 */
public class Telnet extends Task {
    private String user = "anonymous";
    private String password;
    private String host;
    private String command;
    private String prompt;
  
    /** Creates new Telnet Task */
    public Telnet() {
    }

    /**
     * Sets the user or username used to login to the telnet server.
     *
     * @param user the telnet login username.
     */
    public void setUser(String user) {
        this.user = user;
    }
  
    /**
     * Sets the password used to login to the telnet server.
     *
     * @param password the telnet login password.
     */
    public void setPassword(String password) {
        this.password = password;
    }
  
    /**
     * Sets the hostname of the telnet server.
     *
     * @param host the telnet server hostname.
     */
    public void setHost(String host) {
        this.host = host;
    }
  
    /**
     * Sets the shell command to be issued on the remote host.
     *
     * @param command shell command to issue on remote host.
     */
    public void setCommand(String command) {
        this.command = command;
    }

    /**
     * Sets the command prompt expected from the remote host. This defaults to 
"->";
     *
     * @param prompt command prompt.
     */
    public void setPrompt(String prompt) {
        this.prompt = prompt;
    }
  
    /**
     * Executes this telnet task.
     *
     * throws org.apache.tools.ant.BuildException if there is an error during 
task
     *        execution.
     */
    public void execute() {
    
        if (this.host == null) {
            throw new BuildException("Attribute \"host\" is required. This 
should be the hostname of the telnet server.");
        }
        if (this.password == null) {
            throw new BuildException("Attribute \"password\" is required. This 
should be your password on the remote server or your email address if it is an 
anonymous login.");
        }
        if (this.command == null) {
            throw new BuildException("Attribute \"command\" is required. This 
is the command you want to issue on the remote server.");
        }
        if (this.prompt == null) {
            throw new BuildException("Attribute \"prompt\" is required. This is 
the command prompt issue by the remote server. Please be sure to enter this 
correctly, entering as many characters of the prompt as you can, as this makes 
the task wok more reliably.");
        }
    
        TelnetClient telnet = new TelnetClient();
        try {
            log("Connecting to telnet host '" + this.host + "'");
            telnet.connect(this.host, 23);
        } catch (IOException e) {
            throw new BuildException("Failed to connect to remote host - be 
sure that your hostname is correct!");
        }
        
        try {
            BufferedInputStream in = new 
BufferedInputStream(telnet.getInputStream());
            Writer out = new OutputStreamWriter(telnet.getOutputStream());
            BufferedReader input = new BufferedReader(new 
InputStreamReader(System.in));
            
            // FIXME - Currently the code outputs the username and password 
straight away without waiting for a response for the server.  However, many 
servers require the responses to be issues only after the prompts have been 
given. So we need to enter code to deal with that here!
            out.write("\r\n\r\n");
            out.flush();
            waitForResponse(in, "login:");
            log("Entering username");
            out.write(this.user + "\r\n");
            out.flush();
            waitForResponse(in, "assword:"); // NO 'p' as it could be upper or 
lower case.
            log("Entering password");
            out.write(this.password + "\r\n");
            out.flush();
            waitForResponse(in, this.prompt); // Wait for command prompt
            log("Issuing command '" + this.command + "'");
            // XXX - In the longterm it would be better to embed the command 
inside this task so that you could issue multiple commands on the telnet server.
            String fullCommand = this.command + "; echo '[COMPLETED]'";
            out.write(fullCommand +"\r\n");
            out.flush();
            String response = waitForResponse(in, "[COMPLETED]"); // Make sure 
the command has been received.
            log("Response: " + response.substring(0, response.length() - 
"[COMPLETED]".length()));
            // XXX - There is no code here to detect whether the command was 
successfully issues, and to provide feedback to the users. An improved version 
of this code should provide feedback and check that the command has worked, 
perhaps by wrapping it in a standard csh conditional statement which checks for 
success and then returns an output that can be detected by this task and 
translated into a success or failure.
            log("Exiting from Telnet session");
            out.write("exit\r\n");
            out.flush();
            log("Disconnected");
            
            telnet.disconnect();
        } catch(IOException e) {
            // XXX - Nice idea, but it won't get here when I'd like it to!
            throw new BuildException("Failed to login and issue your command - 
make sure your username and password are correct!");
        }
    }
    
    private String waitForResponse(InputStream in, String response) throws 
BuildException, IOException {
        StringBuffer buf = new StringBuffer();
        boolean match = false;
        int c;
        while (! match) {
            c = in.read();
            if (c == -1) {
                throw new BuildException("Telnet host has cancelled connection 
before awaited response '" + response + "'");
            }
            buf.append((char)c);
            if (c == buf.charAt(buf.length()-1)) {
                // Most recently received character is the same as the last 
character of the response to be matched. Check to see whether the complete 
response matches.
                String buffer = buf.toString();
                if (buffer.lastIndexOf(response) != -1) match = true;
            }
        }
        return buf.toString();
    }

}

-------------------------------------------------------------------------
Stuart Roebuck, BSc, MBA        Tel.: 0131 228 4853 / Fax.: 0870 054 8322
Managing Director                       Alpha Numeric Pager: 07654 588898
ADOLOS                                             http://www.adolos.com/

Reply via email to