Eiffel Telnet
Version 1.0
Brian E. Heilig
heilig@iname.com

class TELNET_CLIENT
This is the main class. It is a Telnet client implemented as a state machine. The presentation and network layers have been abstracted for generality. You must provide your own network connection.

When the associated socket becomes readable you should read all of the remote terminal's data into a string and pass it to `on_client_data'. This command will parse the provided string and call the appropriate call-back as necessary.

All known commands will call an on_* call-back. For example, receiving IAC WILL ECHO will result in a call to on_echo. Receiving a terminal-type sub-negotiation will result in a call to on_sub_terminal_type (if you are not familiar with these terms see the bibliography). Anything not interpreted as a command will be appended to data_buffer. When a terminating (new line or carriage return) character is received, or when data_buffer becomes full, on_new_line will be called. The parameter `data' passed to on_new_line will not contain the terminating character.

Commands and data may span across multiple reads.

Commands may be received in the middle of a regular data stream.

on_echo has been implemented as an example, and because it is a common and useful command.

You should inherit from TELNET_CLIENT and redefine any commands you wish to handle. You may also redefine on_command to handle your own commands. When redefining commands make sure validate the passed data.

class TELNET_UTILITIES
This class provides all of the constants you'll need.

cluster example
An example is provided as a Telnet server accepting multiple connections. I'm sure it's not the most robust server in the world, but the intention was only to provide an example for implementing the Telnet client. To that end, inspect the ISE_TELNET_CLIENT class. Check out the redefined on_new_line procedure. In it you will see that several commands have been provided for the remote terminal. Compile the application, execute it, and connect to your server. Try typing in some of the strings listed in on_new_line.

As an example, type `naws' in the terminal, followed by a carriage return. The select will pass and ISE_TELNET_CLIENT.execute will be called by the MEDIUM_POLLER. execute will read in a string of data. If the string is empty then the client has closed his connection. Otherwise pass the string to on_client_data for parsing.

on_client_data will parse the string "naws%R" as regular data (it will not be interpreted as a command) through the various states. When the terminating character '%R' is received then the string "naws" will be passed to the redefined version of on_new_line.

on_new_line will detect the "naws" string and will send the command `do_naws', which is IAC DO NAWS.

Your terminal should receive this command, and respond with IAC WILL NAWS. TELNET_CLIENT will parse this as a command and call on_command.

on_command will parse the command and call on_naws. on_naws does nothing with the command. The protocol states that the window size message should immediately follow. Indeed if you have a conforming terminal, then it will send the window size sub-negotiation. Something like, IAC SB NAWS 0 80 0 40 IAC SE.

TELNET_CLIENT will receive this and parse it as a window size sub negotiation, and call the redefined version of on_sub_window_size.

ISE_TELNET_CLIENT.on_sub_window_size will call TELNET_CLIENT.on_sub_window size which will parse the command and set the window_width, and window_height attributes (in class TELNET_CLIENT). Then ISE_TELNET_CLIENT will send the window width and height back to the remote terminal in the following form:

Window Width: 80
Window Height: 40

License information

All source coded is distributed under tthe terms and conditions of the Eiffel
Forum License:

    Eiffel Forum License, version 2

    1. Permission is hereby granted to use, copy, modify and/or distribute
       this package, provided that:
           * copyright notices are retained unchanged,
           * any distribution of this package, whether modified or not,
             includes this license text.
    2. Permission is hereby also granted to distribute binary programs which
       depend on this package. If the binary program depends on a modified
       version of this package, you are encouraged to publicly release the
       modified version of this package.

    THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY. ANY EXPRESS 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 AUTHORS BE LIABLE TO ANY PARTY FOR
    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THIS PACKAGE.

This license is an OSI Approved License:

    http://opensource.org/licenses/ver2_eiffel.php

and a GPL-Compatible, Free Software License:

    http://www.gnu.org/licenses/eiffel-forum-license-2.html

Bibliography:
RFC 854: Telnet Protocol Specification
RFC 855: Telnet Options Specification
RFC 857: Telnet Echo Option
RFC 859: Telnet Status Option
RFC 1073: Telnet Window Size Option
RFC 1091: Telnet Terminal-Type Option
