2 /* "In case you would like to use the packages as libraries please
3 * apply the GNU Library General Public License as documented in the
4 * file COPYING.LIB." (from Telnet/Documentation/index.html)
8 * telnet -- implements a simple telnet
10 * $Id: telnet.java,v 1.19 1998/02/09 10:22:15 leo Exp $
11 * $timestamp: Mon Aug 4 13:11:14 1997 by Matthias L. Jugel :$
13 * This file is part of "The Java Telnet Applet".
15 * This is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2, or (at your option)
20 * "The Java Telnet Applet" is distributed in the hope that it will be
21 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this software; see the file COPYING. If not, write to the
27 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28 * Boston, MA 02111-1307, USA.
31 import java.applet.Applet;
32 import java.awt.Frame;
33 import java.awt.Component;
34 import java.awt.Container;
35 import java.awt.BorderLayout;
36 import java.awt.Dimension;
37 import java.awt.Panel;
38 import java.awt.Event;
39 import java.util.Vector;
40 import java.util.Hashtable;
41 import java.util.Enumeration;
42 import java.io.IOException;
44 import de.mud.telnet.socket.*;
45 import de.mud.telnet.display.*;
46 import de.mud.telnet.modules.*;
49 * A telnet implementation that supports different terminal emulations.
50 * @version $Id: telnet.java,v 1.19 1998/02/09 10:22:15 leo Exp $
51 * @author Matthias L. Jugel, Marcus Meißner
53 public class telnet extends Applet implements Runnable, TerminalHost, StatusPeer
56 * The telnet io methods.
57 * @see socket.TelnetIO
59 protected TelnetIO tio;
62 * The terminal emulation (dynamically loaded).
64 * @see display.Terminal
65 * @see display.TerminalHost
67 protected Terminal term;
70 * The host address to connect to. This is retrieved from the PARAM tag
73 protected String address;
76 * The port number (default ist 23). This can be specified as the PARAM tag
79 protected int port = 23;
82 * The proxy ip address. If this variable is set telnet will try to connect
83 * to this address and then send a string to tell the relay where the
87 protected String proxy = null;
89 * The proxy port number. This is the port where the relay is expected to
90 * listen for incoming connections.
94 protected int proxyport;
97 * Emulation type (default is vt320). This can be specified as the PARAM
100 * @see display.Terminal
101 * @see display.TerminalHost
103 protected String emulation = "vt320";
106 * Dynamically loaded modules are stored here.
108 protected Vector modules = null;
110 // some state variables;
111 private boolean localecho = true;
112 private boolean connected = false;
115 private Container parent;
118 * This Hashtable contains information retrievable by getParameter() in case
119 * the program is run as an application and the AppletStub is missing.
121 public Hashtable params;
124 * Retrieve the current version of the applet.
125 * @return String a string with the version information.
127 public String getAppletInfo()
129 String info = "The Java(tm) Telnet Applet\n$Id: telnet.java,v 1.19 1998/02/09 10:22:15 leo Exp $\n";
130 info += "Terminal emulation: "+term.getTerminalType()+
131 " ["+term.toString()+"]\n";
132 info += "Terminal IO version: "+tio.toString()+"\n";
133 if(modules != null && modules.size() > 0) {
134 info += "Resident modules loaded: ("+modules.size()+")";
135 for(int i = 0; i < modules.size(); i++)
136 info += " + "+(modules.elementAt(i)).toString()+"\n";
143 * Retrieve parameter tag information. This includes the tag information from
144 * terminal and loaded modules.
145 * @return String an array of array of string with tag information
146 * @see java.applet.Applet#getParameterInfo
148 public String[][] getParameterInfo()
152 {"address", "String", "IP address"},
153 {"port", "Integer", "Port number"},
154 {"proxy", "String", "IP address of relay"},
155 {"proxyport","Integer", "Port number of relay"},
156 {"emulation","String", "Emulation to be used (standard is vt320)"},
158 String tinfo[][] = (term != null ? term.getParameterInfo() : null);
159 if(tinfo != null) pinfo = new String[tinfo.length + 3][3];
160 else pinfo = new String[3][3];
161 System.arraycopy(info, 0, pinfo, 0, 3);
162 System.arraycopy(tinfo, 0, pinfo, 3, tinfo.length);
167 * We override the Applet method getParameter() to be able to handle
168 * parameters even as application.
169 * @param name The name of the queried parameter.
170 * @return the value of the parameter
171 * @see java.applet.Applet#getParameter
173 public String getParameter(String name)
175 if(params == null) return super.getParameter(name);
176 return (String)params.get(name);
180 * The main function is called on startup of the application.
182 public static void main(String args[])
184 // an application has to create a new instance of itself.
185 telnet applet = new telnet();
187 // create params from command line arguments
188 applet.params = new Hashtable();
191 case 2: applet.params.put("port", args[1]);
192 case 1: applet.params.put("address", args[0]);
195 System.out.println("Usage: java telnet host [port]");
198 applet.params.put("VTscrollbar", "true");
199 applet.params.put("module#1", "ButtonBar");
200 applet.params.put("1#Button", "Exit|\\$exit()");
201 applet.params.put("2#Button", "Connect|\\$connect(\\@address@,\\@port@)");
202 applet.params.put("3#Input", "address#30|"
203 +(args.length > 0 ? args[0] : "localhost"));
204 applet.params.put("4#Input", "port#4|23");
205 applet.params.put("5#Button", "Disconnect|\\$disconnect()");
207 // we put the applet in its own frame
208 Frame frame = new Frame("The Java Telnet Application ["+args[0]+"]");
209 frame.setLayout(new BorderLayout());
210 frame.add("Center", applet);
211 frame.resize(380, 590);
222 * Initialize applet. This method reads the PARAM tags "address",
223 * "port" and "emulation". The emulation class is loaded dynamically.
224 * It also loads modules given as parameter "module#<nr>".
230 // save the current parent for future use
231 parent = getParent();
233 // get the address we want to connect to
234 address = getParameter("address");
236 if((tmp = getParameter("port")) == null)
239 port = Integer.parseInt(tmp);
241 if((proxy = getParameter("proxy")) != null)
242 if((tmp = getParameter("proxyport")) == null)
245 proxyport = Integer.parseInt(tmp);
247 if((emulation = getParameter("emulation")) == null)
250 // load the terminal emulation
252 term = (Terminal)Class.forName("display."+emulation).newInstance();
253 System.out.println("telnet: load terminal emulation: "+emulation);
254 } catch(Exception e) {
255 System.err.println("telnet: cannot load terminal emulation "+emulation);
258 setLayout(new BorderLayout());
260 // load modules, position is determined by the @<position> modifier
261 modules = new Vector();
263 while((tmp = getParameter("module#"+nr++)) != null) try {
264 Panel north = null, south = null, west = null, east = null;
265 String position = "North", initFile = null;
267 // try to get the initialization file name
268 if(tmp.indexOf(',') != -1) {
269 initFile = tmp.substring(tmp.indexOf(','+1));
270 tmp = tmp.substring(0, tmp.indexOf(','));
271 initFile = tmp.substring(tmp.indexOf(','+1));
274 // find the desired location
275 if(tmp.indexOf('@') != -1) {
276 position = tmp.substring(tmp.indexOf('@')+1);
277 tmp = tmp.substring(0, tmp.indexOf('@'));
279 Object obj = (Object)Class.forName("modules."+tmp).newInstance();
281 // probe for module (implementing modules.Module)
283 ((Module)obj).setLoader(this);
284 modules.addElement((Module)obj);
285 System.out.println("telnet: module "+tmp+" detected");
286 } catch(ClassCastException e) {
287 System.out.println("telnet: warning: "+tmp+" may not be a "+
291 // probe for visible component (java.awt.Component and descendants)
293 Component component = (Component)obj;
294 if(position.equals("North")) {
295 if(north == null) { north = new Panel(); add("North", north); }
296 north.add(component);
297 } else if(position.equals("South")) {
298 if(south == null) { south = new Panel(); add("South", south); }
299 south.add(component);
300 } else if(position.equals("East")) {
301 if(east == null) { east = new Panel(); add("East", east); }
303 } else if(position.equals("West")) {
304 if(west == null) { west = new Panel(); add("West", west); }
307 System.err.println("telnet: module "+tmp+" is a visible component");
308 } catch(ClassCastException e) {}
310 } catch(Exception e) {
311 System.err.println("telnet: cannot load module "+tmp);
314 if(modules.isEmpty()) modules = null;
319 * Upon start of the applet try to create a new connection.
323 if(!connect(address, port) && params == null)
324 showStatus("telnet: connection to "+address+" "+port+" failed");
328 * Disconnect when the applet is stopped.
330 public final void stop()
336 * Try to read data from the sockets and put it on the terminal.
337 * This is done until the thread dies or an error occurs.
343 String tmp = new String(tio.receive(), 0);
345 // cycle through the list of modules
346 if(modules != null) {
347 Enumeration modlist = modules.elements();
348 while(modlist.hasMoreElements()) {
349 Module m = (Module)modlist.nextElement();
350 String modified = m.receive(tmp);
351 // call the receive() method and if it returns null
352 // remove the module from the list
353 if(modified == null) modules.removeElement(m);
357 // put the modified string to the terminal
359 } catch(IOException e) {
365 * Connect to the specified host and port but don't break existing
366 * connections. Connects to the host and port specified in the tags.
367 * @return false if connection was unsuccessful
369 public boolean connect()
371 return connect(address, port);
375 * Connect to the specified host and port but don't break existing
376 * connections. Uses the port specified in the tags or 23.
377 * @param host destination host address
379 public boolean connect(String host)
381 return connect(host, port);
385 * Connect to the specified host and port but don't break existing
387 * @param host destination host address
388 * @param prt destination hosts port
390 public boolean connect(String host, int prt)
392 address = host; port = prt;
394 if(address == null || address.length() == 0) return false;
396 // There should be no thread when we try to connect
397 if(t != null && connected) {
398 System.err.println("telnet: connect: existing connection preserved");
403 // In any case try to disconnect if tio is still active
404 // if there was no tio create a new one.
405 if(tio != null) try { tio.disconnect(); } catch(IOException e) {}
406 else (tio = new TelnetIO()).setPeer(this);
408 term.putString("Trying "+address+(port==23?"":" "+port)+" ...\n\r");
410 // connect to to our destination at the given port
412 tio.connect(proxy, proxyport);
413 String str = "relay "+address+" "+port+"\n";
414 byte[] bytes = new byte[str.length()];
415 str.getBytes(0, str.length(), bytes, 0);
418 tio.connect(address, port);
419 term.putString("Connected to "+address+".\n\r");
420 // initial conditions are connected and localecho
424 // cycle through the list of modules and notify connection
425 if(modules != null) {
426 Enumeration modlist = modules.elements();
427 while(modlist.hasMoreElements())
428 // call the connect() method
429 ((Module)modlist.nextElement()).connect(address, port);
431 } catch(IOException e) {
432 term.putString("Failed to connect.\n\r");
433 // to be sure, we remove the TelnetIO instance
435 System.err.println("telnet: failed to connect to "+address+" "+port);
439 // if our connection was successful, create a new thread and start it
440 t = new Thread(this);
441 t.setPriority(Thread.MIN_PRIORITY);
443 } catch(Exception e) {
444 // hmm, what happened?
445 System.err.println("telnet: an error occured:");
453 * Disconnect from the remote host.
454 * @return false if there was a problem disconnecting.
456 public boolean disconnect()
459 System.err.println("telnet: no connection");
463 connected = false; t = null;
464 // cycle through the list of modules and notify connection
465 if(modules != null) {
466 Enumeration modlist = modules.elements();
467 while(modlist.hasMoreElements())
468 // call the disconnect() method
469 ((Module)modlist.nextElement()).disconnect();
471 term.putString("\n\rConnection closed.\n\r");
473 } catch(Exception e) {
474 System.err.println("telnet: disconnection problem");
476 tio = null; t = null;
483 * Send a String to the remote host. Implements display.TerminalHost
484 * @param s String to be sent
485 * @return true if we are connected
486 * @see display.TerminalHost
488 public boolean send(String str)
491 byte[] bytes = new byte[str.length()];
492 str.getBytes(0, str.length(), bytes, 0);
495 if ((str.length()==2) && (str.charAt(0)=='\r') && (str.charAt(1)==0))
496 term.putString("\r\n");
500 } catch(Exception e) {
501 System.err.println("telnet.send(): disconnected");
510 * Send a String to the remote Host.
511 * @param str String to be sent
512 * @return true if we are connected
513 * @see modules.BSXModule
515 public boolean writeToSocket(String str)
518 byte[] bytes = new byte[str.length()];
519 str.getBytes(0, str.length(), bytes, 0);
521 } catch(Exception e) {
522 System.err.println("telnet.send(): disconnected");
530 * Send a String to the users terminal
531 * @param str String to be displayed
533 * @see modules.BSXModule
535 public void writeToUser(String str)
542 * This method is called when telnet needs to be notified of status changes.
543 * @param status Vector of status information.
544 * @return an object of the information requested.
545 * @see socket.StatusPeer
547 public Object notifyStatus(Vector status)
549 String what = (String)status.elementAt(0);
550 if(what.equals("NAWS"))
551 return term.getSize();
552 if(what.equals("TTYPE"))
553 if(term.getTerminalType() == null)
555 else return term.getTerminalType();
556 if(what.equals("LOCALECHO"))
558 if(what.equals("NOLOCALECHO"))