Bill Brendling
At the beginning of November, Dave set a challenge:
A potential new MFX user asked whether there was a Telnet client available for MFX. I said "no", but then got to thinking, would it be possible? Obviously, not by me with my programming "skills", but for someone with past "C", CP/M and MFX experience - maybe?
Do you think that this would be possible, and if so, do you fancy the challenge ?
The guy started off asking if MFX could do RS232. I said that it couldn’t and asked why he needed that, his reply was . . . . .
The serial port requirement is so that I can plug in a wimodem232pro so that I can telnet to either my BBS or other’s BBSes.
Looking at the spec of the MFX, I think I can use the networking capabilities of that to do the same as the wimodem232pro as long as I can find or there is included some sort of telnet client? (Preferably with ANSI / VT100 support).
Having a bit of spare time I decided to see what I could achieve. It should be noted that both the full telnet specification and the ANSI display specification are complex standards. The CP/M telnet client I have produced is by no means a full implementation of either standard (see the technical notes section). However, hopefully it has enough functionality to be of use for some applications.
Many systems accessible using telnet will assume a PC character set. It will often be useful to load an appropriate font using loadfont prior to running telnet.
To start the telnet client use a command of the form:
telnet [<switches>] <ip-address>[:<port>]
where the angle brackets surround items to be replaced, and the square brackets indicate optional items. Neither type of bracket form part of the final command.
The ip-address must be specified in dotted decimal form (1.2.3.4). Performing a DNS lookup to convert a domain name to an ip-address is a whole other problem.
The ip-address my be followed by a colon and then a port number. If the port number is omitted, then port 23 (the telnet port) is assumed.
The following switches are supported:
| Switch | Description |
|---|---|
| -a | Use the right shift key as an <Alt> key. |
| -e | Log all unrecognised <Esc> sequences in the log file (if enabled). |
| -l <filename.log> | Log information to the specified file. |
| -m | Log information to the MEMU log file (assuming running on MEMU with -diag-chip-log). |
| -r | Log all received network data. |
| -t | Log all transmitted network data. |
| -v | Display program version and then exit. |
The options may be specified in upper case as well as lower.
Logging, if enabled, will always include details of all telnet negotiations.
Therefore a typical command to start the telnet client might be:
telnet -e -l telnet.log 192.168.0.1
Once started, the MFX display is switched to 64 colour mode to support ANSI colour requests as best as the MFX is able.
While running the telnet client, as well as the option to use the right shift key as <Alt>, the MTX editing keypad is used as follows:
| Page Up | End | Abort |
| Tab | Csr Up | Del |
| Csr Left | Home | Csr Right |
| Ins | Csr Down | Page Down |
The Abort key sends a telnet "Abort Output" command. All the other keypad keys send the corresponding keystroke to the telnet server.
Usually you will issue a logout command to the telnet server. This will close the connection, after which the telnet client will exit and return to CP/M. Since the ANSI screen driver is talking directly to the MFX hardware, CP/M would not know the screen state. It is therefore necessary to clear the screen to reset the CP/M screen driver.
As mentioned, this version is nowhere near a complete implementation of the ANSI specification. For commands that are not implemented, it mostly knows how to skip over and ignore them. However, in some cases it might get stuck, and think it is in the middle of an escape sequence that never ends. In that case, there are two options for recovering, both of which involve simultaneously pressing two function keys;
| Keys | Action |
|---|---|
| <F1> + <F5> | Resets the ANSI driver to a known state. It should start displaying characters again, although the screen layout will probably be corrupted. |
| <F4> + <F8> | Closes the telnet client and returns to CP/M. |
These key combinations will only work providing the program main loop is still running. If not, it will be necessary to reset the MTX.
The telnet protocol is very old. Over the years it has acquired many optional features. See:
The MFX client supports a minimal number of these options:
| Option | Description |
|---|---|
| DO 0 | Send <CR> without following <LF>. |
| DO 24 | Send terminal type. Only one type is offered: ANSI. |
| DO 31 | Send window size. Sends a fixed size of 24x80. |
| WILL 1 | Suppress local echo of typed characters. |
| WILL 3 | Suppress telnet "Go Ahead" signal. |
The official ECMA-48 standard for ANSI screen control is very extensive, defining hundreds of escape sequences for defining different features of the display. Even worse, there have been lots of additional private sequences defined by companies such as Digital Equipment Corporation (DEC) which have become widely adopted. See:
The ANSI driver in the MFX telnet only implements a small subset of these sequences, chosen because they are believed to be most often used. This choice was primarily based upon thos codes documented on Wikipedia together with some experimentation with a few typical devices. For sequences that are not implemented, the driver tries to skip over them without displaying any spurious characters, assuming that they conform to the standard format.
As well as being used to control screen layout, escape sequences are used to send non-printing keystrokes to the telnet service. It proves difficult to find complete documentation of the sequencies used, and there appears to be multiple standards. The following sequences have been adopted for the MFX telnet:
| Key | Escape Sequence | With modifier keys |
|---|---|---|
| Cursor up | <Esc> [ A | <Esc> [ 1 ; m A |
| Cursor down | <Esc> [ B | <Esc> [ 1 ; m B |
| Cursor right | <Esc> [ C | <Esc> [ 1 ; m C |
| Cursor left | <Esc> [ D | <Esc> [ 1 ; m D |
| Home | <Esc> [ H | <Esc> [ 1 ; m H |
| End | <Esc> [ F | <Esc> [ 1 ; m F |
| Ins | <Esc> [ 2 ~ | <Esc> [ 2 ; m ~ |
| Del | <Esc> [ 3 ~ | <Esc> [ 3 ; m ~ |
| Page Up | <Esc> [ 5 ~ | <Esc> [ 5 ; m ~ |
| Page Down | <Esc> [ 6 ~ | <Esc> [ 6 ; m ~ |
| F1 | <Esc> [ 1 1 ~ | <Esc> [ 1 1 ; m ~ |
| F2 | <Esc> [ 1 2 ~ | <Esc> [ 1 2 ; m ~ |
| F3 | <Esc> [ 1 3 ~ | <Esc> [ 1 3 ; m ~ |
| F4 | <Esc> [ 1 4 ~ | <Esc> [ 1 4 ; m ~ |
| F5 | <Esc> [ 1 5 ~ | <Esc> [ 1 5 ; m ~ |
| F6 | <Esc> [ 1 7 ~ | <Esc> [ 1 7 ; m ~ |
| F7 | <Esc> [ 1 8 ~ | <Esc> [ 1 8 ; m ~ |
| F8 | <Esc> [ 1 9 ~ | <Esc> [ 1 9 ; m ~ |
| Shift F1 | <Esc> [ 2 0 ~ | <Esc> [ 2 0 ; m ~ |
| Shift F2 | <Esc> [ 2 1 ~ | <Esc> [ 2 1 ; m ~ |
| Shift F3 | <Esc> [ 2 3 ~ | <Esc> [ 2 3 ; m ~ |
| Shift F4 | <Esc> [ 2 4 ~ | <Esc> [ 2 4 ; m ~ |
| Shift F5 | <Esc> [ 2 5 ~ | <Esc> [ 2 5 ; m ~ |
| Shift F6 | <Esc> [ 2 6 ~ | <Esc> [ 2 6 ; m ~ |
| Shift F7 | <Esc> [ 2 8 ~ | <Esc> [ 2 8 ; m ~ |
| Shift F8 | <Esc> [ 2 9 ~ | <Esc> [ 2 9 ; m ~ |
In the table above, if the key in the left hand column is pressed, then the escape sequence in the middle column is transmitted. If any of the modifier keys (<Shift>, <Ctrl> or <Alt>) are also pressed, then the escape sequence in the right hand column is transmitted, where m is replaced by the character from the following table:
| m | Modifier keys |
|---|---|
| 2 | Shift |
| 3 | Alt |
| 4 | Shift + Alt |
| 5 | Ctrl |
| 6 | Shift + Ctrl |
| 7 | Alt + Ctrl |
| 8 | Shift + Alt + Ctrl |
For printable keys (including space), they are transmitted by their usual ASCII code, modified by <Shift> and <Ctrl> in the usual way. If the <Alt> key is also down, then the ASCII code is preceeded by an <Esc> code.