package socket; import java.io.IOException; import java.util.Date; /** Wrapper for a Java Telnet call. * To use, make a new TelnetWrapper() with the name or IP address of a host. * Then, for most uses, the easiest way is to call setPrompt() with the * expected prompt, then call login(), and a sequence of sendLine()'s * until you get what you want done. * <P> * If you don't know the prompt ahead of time, you have to do a sequence of * send() and wait() or receiveUntil() calls. send() sends a string across * the telnet connection. Add a '\r' to the end if you want to * complete a command. wait() waits for an exact string from the other side * of the telnet connection, and returns nothing, * receiveUntil() also waits for a string, but returns all the data * that it received while waiting, including the string itself. * Use this if you want the output from a command. Please note that * the telnet connection will usually echo the sent command. * <P> * sendLine() is generally better, since it adds the '\r' * automatically, waits for the prompt before returning, and returns all * data received before the prompt, with the prompt itself cut off the * end, and the sent command cut off the beginning. login() and * sendLine() are implemented using send(), wait() and receiveUntil(). * They can be freely mixed and matched. * <P> * Here is a simple example of the use of TelnetWrapper: * <PRE> * // creates a new file in /tmp, lists the directory to prove it done * { * TelnetWrapper telnet = new TelnetWrapper("123.45.78.90"); * * // setting the correct prompt ahead of time is very important * // if you want to use login and sendLine * telnet.setPrompt("$ "); * telnet.login("loginname", "password"); * * // this is how you have to do it otherwise * telnet.send("touch /tmp/TELNET_WRAPPER" + "\r"); * telnet.wait("$ "); * * // sendLine 1: adds the \r automatically, 2: waits for the prompt * // before returning 3: returns what was printed from the command * String ls = telnet.sendLine("ls /tmp"); * System.out.println(ls); * * // clean up * telnet.disconnect(); * } * </PRE> * @author George Ruban 3/4/97 * @version 0.2 5/15/97 - added comments, replaced String += with * StringBuffer.append() in receiveUntil(), added port constructor * @version 0.3 7/30/97 - added optional timeout to receiveUntil() and wait() * @see TelnetIO */ public class TelnetWrapper { /** The telnet connection. That which is wrapped. */ TelnetIO tio; /** Set to true for System.out.println debugging. */ public boolean debug = false; /** The current prompt on the remote system. */ private String prompt; /** The default prompt used by all TelnetWrappers unless specifically * overridden. * @see #setPrompt */ private static String defaultPrompt = "$ "; /** The default login name used by TelnetWrappers. * If defaultLogin and defaultPassword are both non-null * when a TelnetWrapper is created, the TelnetWrapper will attempt * to login. */ private static String defaultLogin = null; /** The default password used by TelnetWrappers. * If defaultLogin and defaultPassword are both non-null * when a TelnetWrapper is created, the TelnetWrapper will attempt * to login. */ private static String defaultPassword = null; /** Skip any received data until the token appears. * More efficient than receiveUntil, but liable to fail on large * tokens that can be spread over several "send"s. In that case, * consider using receiveUntil and ignoring the return value. * @param token String to wait for * @exception IOException on problems with the socket connection * @see #receiveUntil */ public void wait(String token) throws IOException { wait(token, -1); } /** Wait for a String or a timeout. * If time runs out, throws a TimedOutException. * Sleeps in intervals of 100 milliseconds until either receiving the * token or timeout. * <P> * More efficient than receiveUntil, but liable to fail on large * tokens that can be spread over several "send"s. In that case, * consider using receiveUntil and ignoring the return value. * @param token String to wait for * @param timeout time in milliseconds to wait (negative means wait forever) * @exception IOException on problems with the socket connection * @exception TimedOutException if time runs out before token received * @see #receiveUntil(String, long) */ public void wait(String token, long timeout) throws IOException, TimedOutException { if(debug) System.out.println("wait(" + token + ", " + timeout + ")..."); String tmp = ""; long deadline = 0; if(timeout >= 0) deadline = new Date().getTime() + timeout; do { if(timeout >= 0) { while(available() <= 0) { if(new Date().getTime() > deadline) throw new TimedOutException(); try{ Thread.currentThread().sleep(100); } catch(InterruptedException ignored) {} } } tmp = receive(); } while(tmp.indexOf(token) == -1); if(debug) System.out.println("wait(" + token + ", " + timeout + ") successful."); } /** Returns bytes available to be read. Since they haven't been * negotiated over, this could be misleading... */ public int available() throws IOException { return tio.available(); } /** Returns a String from the telnet connection. Blocks * until one is available. No guarantees that the string is in * any way complete. * NOTE: uses Java 1.0.2 style String-bytes conversion.*/ public String receive() throws IOException { String s = new String(receiveBytes(), 0); if(debug) System.out.println(s); return s; } /** Returns a byte array. Blocks until data is available. */ public byte[] receiveBytes() throws IOException { return tio.receive(); } /** Returns all data received up until a certain token. * @param token String to wait for * @exception IOException on problems with the socket connection * @see #wait */ public String receiveUntil(String token) throws IOException { return receiveUntil(token, -1); } /** Returns all data received up until a certain token. * @param token String to wait for * @param timeout time in milliseconds to wait (negative means wait forever) * @exception IOException on problems with the socket connection * @exception TimedOutException if time runs out before token received * @see #wait(String, long) */ public String receiveUntil(String token, long timeout) throws IOException, TimedOutException { StringBuffer buf = new StringBuffer(); long deadline = 0; if(timeout >= 0) deadline = new Date().getTime() + timeout; do { if(timeout >= 0) { while(available() <= 0) { if(new Date().getTime() > deadline) throw new TimedOutException(); try{ Thread.currentThread().sleep(100); } catch(InterruptedException ignored) {} } } buf.append(receive()); } while(buf.toString().indexOf(token) == -1); return buf.toString(); } /** Sends a String to the remote host. * NOTE: uses Java 1.0.2 style String-bytes conversion. * @exception IOException on problems with the socket connection */ public void send(String s) throws IOException { if(debug) System.out.println(s); byte[] buf = new byte[s.length()]; s.getBytes(0, buf.length, buf, 0); tio.send(buf); } /** Sends a line to the remote host, returns all data before the prompt. * Since telnet seems to rely on carriage returns ('\r'), * one will be appended to the sent string, if necessary. * @param command command line to send * @return whatever data the command produced before the prompt. * @see #setPrompt */ public String sendLine(String command) throws IOException { if(command.charAt(command.length() -1) != '\r') command += "\r"; send(command); String s = receiveUntil(prompt); // telnet typically echoes the command with a \r\n ending... return s.substring(command.length() + 1, s.indexOf(prompt)); } /** Sends bytes over the telnet connection. */ public void send(byte[] buf) throws IOException { tio.send(buf); } /** Logs in as a particular user and password. * Returns after receiving prompt. */ public void login(String loginName, String password) throws IOException { wait("login:"); send(loginName + "\r"); wait("Password:"); sendLine(password + "\r"); } /** Connects to the default telnet port on the given host. * If the defaultLogin and defaultPassword are non-null, attempts login. */ public TelnetWrapper(String host) throws IOException { tio = new TelnetIO(); setPrompt(defaultPrompt); tio.connect(host); if(defaultLogin != null && defaultPassword != null) { login(defaultLogin, defaultPassword); } } /** Connects to a specific telnet port on the given host. * If the defaultLogin and defaultPassword are non-null, attempts login. */ public TelnetWrapper(String host, int port) throws IOException { tio = new TelnetIO(); setPrompt(defaultPrompt); tio.connect(host, port); if(defaultLogin != null && defaultPassword != null) { login(defaultLogin, defaultPassword); } } /** Sets the expected prompt. * If this function is not explicitly called, the default prompt is used. * @see #setDefaultPrompt */ public void setPrompt(String prompt) { if(prompt == null) throw new IllegalArgumentException("null prompt."); this.prompt = prompt; } /** Sets the default prompt used by all TelnetWrappers. * This can be specifically overridden for a specific instance. * The default prompt starts out as "$ " until this function is called. * @see #setPrompt */ public static void setDefaultPrompt(String prompt) { if(prompt == null) throw new IllegalArgumentException("null prompt."); defaultPrompt = prompt; } /** Sets the default login used by TelnetWrappers. * If this method is called with non-null login and password, * all TelnetWrappers will attempt to login when first created. * @param login login name to use * @param password password to use * @see #login * @see #unsetLogin */ public static void setLogin(String login, String password) { if(login == null || password == null) throw new IllegalArgumentException("null login or password."); defaultLogin = login; defaultPassword = password; } /** Turns off the default login of TelnetWrappers. * After this method is called, TelnetWrappers will not * login until that method is explicitly called. * @see #setLogin * @see #login */ public static void unsetLogin() { defaultLogin = defaultPassword = null; } /** Ends the telnet connection. */ public void disconnect() throws IOException { if(tio != null) tio.disconnect(); tio = null; } /** Ends the telnet connection. */ public void finalize() { try { disconnect(); } catch(IOException e) {} // after all, what can be done at this point? } /** Telnet test driver. * Modeled after the IOtest.java example in the Telnet Applet. * Logs in to "host", creates a timestamped file in /tmp, lists the * /tmp directory to System.out, disconnects. Shows off several * TelnetWrapper methods. * @param args host login password prompt */ public static void main(String args[]) throws IOException { if(args.length != 4) throw new IllegalArgumentException("Usage: TelnetWrapper host login password prompt"); String host = args[0]; String login = args[1]; String password = args[2]; String prompt = args[3]; Date now = new Date(); String timestamp = now.getYear() + "-" + (now.getMonth()+1) + "-" + now.getDate() + "-" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(); TelnetWrapper telnet = new TelnetWrapper(host); telnet.debug = true; // setting the correct prompt ahead of time is very important // if you want to use login and sendLine telnet.setPrompt(prompt); telnet.login(login, password); // this is how you have to do it otherwise telnet.send("touch /tmp/TELNET_WRAPPER-" + timestamp + "\r"); telnet.wait(prompt); // sendLine 1: adds the \r automatically, 2: waits for the prompt // before returning 3: returns what was printed from the command String ls = telnet.sendLine("ls /tmp"); System.out.println(ls); // clean up telnet.disconnect(); } }