This is an unofficial fork of the Telnet application from Michael B. Brutman's mTCP. It adds:
- Enhanced Keyboard support
- Mouse and clipboard support
- Translation of incoming Unicode characters
- Sixel graphics
- Printer support
The binary is available as the TELNET.EXE file and the TELNETNU.EXE file, which are in the bin directory. The TELNETNU.EXE file is the same as TELNET.EXE except that it disables Unicode translation.
The fork is based on the mTCP-src_2022-07-01.zip version of mTCP.
The purpose of this repository is to expand the ansi
terminal
emulation capabilities of mTCP's Telnet application. Where a
feature is not supported by the ansi
standard, ideas are borrowed
from the xterm
standard.
The following keys are transmitted:
- Function keys F1-F12;
- Insert, Delete, Home, End, Page Up, Page Down;
- Cursor keys;
- Shift, Ctrl, Ctrl-shift, Alt, and Alt-Shift modifications of the above;
- Tab, Ctrl-Tab, Shift-Tab;
- Ctrl-Backspace;
- Ctrl-Space; and
- Ctrl-PrtScr.
In the official mTCP, Page Up and Page Down scroll are not passed through but are used for scrolling through the output history. In this version, that function is moved to the Alt-Page Up and Alt-Page Down keys (or Ctrl-Page Up and Ctrl-Page Dn if the Enhanced Keyboard is not available), and Page Up and Page Down are passed through to the server.
For compatibility with Emacs, all Alt-(key) combinations that are not used by the Telnet application are passed through as ESC-(key).
The Delete key is passed through as ESC [ 3 ~
instead of the default
of character 127.
Some of the above keys are not available if your computer lacks support for the Enhanced Keyboard.
Mouse support is available in two forms.
First, if the server sends back xterm
DECSET signals to enable
mouse tracking, mouse activity is transmitted to the server using
xterm
escape sequences. Emacs sends these sequences when
xterm-mouse-mode
is in use, and Vim sends them when set mouse=a
is used. Midnight Commander provides mouse support if the -x
switch
is used to enable xterm
mode.
Second, if the DECSET signals are not received, mouse activity does not result in escape sequences sent to the terminal, but the mouse can be used for copying and pasting. The controls are:
- Left-click and drag to select a region;
- Right-click to extend a selection;
- Double-click to select a word;
- Triple-click to select a line; and
- Middle-click to paste the selection.
Clicking the left and right mouse buttons at the same time emulates the middle mouse button.
For mouse support to work, you may need to install a mouse driver (typically MOUSE.COM) before running TELNET.EXE or TELNETNU.EXE.
When UTF-8 characters are received, they are translated if possible
into one of the 256 characters that can be displayed in text mode. By
default, Unicode characters are translated into Code Page 437. If
no translation is available, a default character, ¿
, is printed.
Unicode translation does not take place when sending outbound characters.
If you are connected to server that sends "extended ASCII" characters
(codes greater than 127) with the expectation that your Telnet client
will display them directly to video memory (e.g., as Code Page 437
character), TELNET.EXE
will misinterpret these codes as the
first byte of a Unicode sequence. Thus, you will get garbage on the
screen. If you need to to connect to a server that sends "extended
ASCII" characters, use TELNETNU.EXE
.
The Code Page and the default unprintable character are
configurable in the MTCP.CFG
file using the directives
TELNET_UTF
, TELNET_CODEPAGE
, and TELNET_UTF_DEFAULT
. For
example, the following excerpt demonstrates enabling Code Page 737
translation in place of the default Code Page 437, and setting the
default character for unprintable Unicode sequences to the space
(0x20).
TELNET_CODEPAGE 737
TELNET_UTF_DEFAULT 0x20
TELNET_UTF 737 0x0000 0x00
TELNET_UTF 737 0x0001 0x01
TELNET_UTF 737 0x0002 0x02
TELNET_UTF 737 0x0003 0x03
...
TELNET_UTF 737 0x00a0 0xff
There are complete example configurations in the config
folder for
Code Page 737, Code Page 775, Code Page 850, Code Page 852,
Code Page 855, Code Page 857 Code Page 860, Code Page 861,
Code Page 862, Code Page 863, Code Page 864, Code Page 865,
Code Page 866, Code Page 869, and Code Page 874. A file is also
included for Code Page 437 in case you want to customize the default
translation.
You can copy and paste from these files into your MTCP.CFG
file.
The TELNET_CODEPAGE
directive selects a code page, and any
directives beginning with TELNET_UTF
will be used to define the
translations that are used. The format of each line is:
TELNET_UTF <CODE_PAGE_NUMBER> <UNICODE_NUMBER> <CHARACTER_NUMBER>
where CODE_PAGE_NUMBER
is the number of the code page (e.g. 737),
the UNICODE_NUMBER
is a hexadecimal Unicode number (e.g., 0x266a
for the musical note character) and CHARACTER_NUMBER
is a
hexadecimal 8-bit number representing the character on the screen
(e.g., 0x0d
for the musical note character). Note that the
TELNET_CODEPAGE
directive will not have any effect in the absence of
TELNET_UTF
lines that define the translations for the code page.
For best results, sort your TELNET_UTF
lines by the Unicode
numbers. If they are out of order, they will need to be sorted when
Telnet starts, which extends the start time.
The TELNET_UTF_DEFAULT
directive indicates which character should be
printed if there is no translation for a particular Unicode character.
The number must be written in hexadecimal. The default is 0xa8
,
which is the character ¿ in Code Page 437.
If you switch between code pages, you can keep definitions for several
code pages in your MTCP.CFG
file and change only the
TELNET_CODEPAGE
line when you want to switch among them.
Depending on what applications you use and what content you view, you may wish to modify the standard Unicode translations, add additional characters, or add additional code pages.
The code page translations in the config
folder were created using
translation tables available on unicode.org.
If a Sixel graphics escape sequence is encountered, the image will be downloaded and then displayed on the screen. It may take significant time for the image to download. While the image is downloading, the screen is unchanged; this is so that you can keep reading what is on the screen while you wait for the graphics image to appear. After viewing the image, you can then press any key to get back to text mode.
The supported graphics modes are:
- 720x348x2 - requires a Hercules Graphics Card
- 320x200x256 - requires VGA or MCGA
- 640x480x2 - requires VGA or MCGA
- 320x200x4 - CGA
- 640x200x2 - CGA
Telnet will use the highest resolution graphics mode available, given the number of colors in the image. If there are two colors, it will use a two-color graphics mode. If there are four colors, it will use a 320x200x4 mode with the matching palette.
Telnet does not autodetect whether you have a Hercules Graphics Card, VGA, or MCGA. By default, it assumes you have VGA or MCGA and it will try to display images in the VGA/MCGA modes.
If your computer does not support the VGA/MCGA modes, you will
need to add a line to your MTCP.CFG
file to stop it from using those
modes. If you have a CGA adapter, set the following:
TELNET_CGA 1
If you have a Hercules Graphics Card, set the following instead:
TELNET_HGC 1
Telnet will not do any image resizing or dithering. If an image is wider or taller than the graphics mode supports, then it will not display.
For best results when connected to a Linux machine, use the included
show script to convert an image file to Sixel escape sequences.
This script calls the img2sixel
command with the appropriate
parameters for resizing images and converting colors.
Without any parameters, show will display an image in 256 colors.
show my_image.png
If you have the Hercules Graphics Card, use the --hercules
switch:
show --hercules my_mono_image.png
If you have CGA graphics only, use the --cga
switch so that color
images are reduced to four colors.
show --cga my_image.png
By default, show will use the bright cyan/magenta/white palette in
--cga
mode. You can tell it to use a different palette with the
--colors
switch:
show --colors CyanMagenta my_image.png
show --colors LightCyanMagenta my_image.png
show --colors GreenRed my_image.png
show --colors LightGreenRed my_image.png
To make an image display in monochrome, use the --mono
switch:
show --mono my_mono_image.png
By default, the --mono
switch will shrink the image to fit in
640x480, which VGA and MCGA monitors can display. If you have
CGA only, make sure to include the --cga
switch:
show --mono --cga my_mono_image.png
This will resize the image to fit within CGA's 640x200 resolution.
With the --me
parameter, show will take a picture with
/dev/video0
and then display it:
show --me
To see the usage instructions, call show
with the --help
switch.
show --help
For instructions on installing the show utility and integrating it with applications, see the Setup section below.
The show utility is a bash script, so you can edit it. You can change the script so that you do not have to provide any flags to get the image format you want.
Historically, the typewriter preceded the computer, and the first
terminals acted like typewriters, printing characters to paper rather
than to a screen. Early video terminals, like the VT52 and VT100,
supported connecting a printer to the terminal, and could switch into
a mode in which incoming characters were sent to the printer and the
user could create a "hardcopy" of the session. When the VT100
terminal received ESC [ 5 i
, all characters received thereafter
would be relayed to the attached printer. When the terminal received
ESC [ 4 i
, the terminal would stop relaying the characters to the
printer. The ansi
and xterm
protocols incorporated this feature.
This version of mTCP Telnet has been modified to provide support for
this method of printing. By default, printing is disabled, however,
so that even if the remote server sends ESC [ 5 i
, the printer will
not print anything. Pressing Alt-P toggles the enabling and disabling
of printing. You can see whether printing is enabled by visiting the
help screen (Alt-H). If printing is enabled and the remote server
sends ESC [ 5 i
, Telnet will start sending all received characters
to the LPT1 printer. It will continue to do so until it receives ESC [ 4 i
. Characters will also be sent to the screen.
If your printer requires initialization, you can add a
TELNET_PRINTER_INIT
line to your MTCP.CFG
file, listing a series
of ASCII characters expressed as two-digit hexadecimal numbers
separated by commas. For example, these are printer initialization
codes for a Diablo 630 printer.
TELNET_PRINTER_INIT 1b,51,0d,1b,1f,0b,1b,1e,09,1b,35
Up to sixteen ASCII characters can be defined using
TELNET_PRINTER_INIT
. These characters are sent to the printer the
first time you type Alt-P to enable printing.
This repository contains a Python script, tprint, that can be used to print a file or an output stream. You can call it either as a pipe or you can give it the name of one or more files:
ps ax | tprint
tprint foo.txt
tprint foo.txt bar.txt
tprint *.msg
In addition, this repository contains two bash scripts, startprint and stopprint, which echo the escape sequences for turning printing on and off. As explained in "Configuring your applications," below, you can also bind keys in bash for turning printing on and off.
This package has been tested on:
- IBM PS/2 Model 25 with an 8086 processor running PC-DOS 4.0 and Microsoft Mouse Driver (MOUSE.COM) version 7.03.
- IBM PC model 5150 with the Hercules Graphics Card.
Unfortunately, I do not have access to other machines, so I do not know what problems may arise on other systems. Please feel free to create GitHub issues to let me know what doesn't work.
As discussed above, you will need to add TELNET_HGC 1
or
TELNET_CGA 1
to your MTCP.CFG
file if you have a Hercules
Graphics Card or CGA adapter in your system.
EGA is currently not supported, because I do not own an EGA card or EGA-compatible monitor.
This version of mTCP Telnet is not as fast as the official mTCP Telnet, so you may see that screens do not draw as fast.
The reason for the slowness is due to the increased feature support. In the main loop of the Telnet application, there are more if/else statements that need to run in order to support additional incoming escape sequences, process multi-byte Unicode sequences, support the mouse feature, and support the printing feature.
If the server you are connected to sends UTF-8 instead of Code Page 437 "extended ASCII" characters, it will send two or three bytes instead of one byte to draw one character, so screen draws may appear slower just because more bytes need to be transferred.
If you can think of ways the code can run more efficiently while supporting the same set of features, feel free to create a GitHub pull request.
In order for your Telnet client and remote servers to communicate
effectively using escape sequences for colors, mouse support, and
keypresses, the remote machines will need to know the precise
capabilities of your Telnet client. On Linux, terminal capabilites
are defined in a "terminfo" file. The TERM
variable in your remote
shell environment tells the remote machine which "terminfo" file to
use. TERM
is typically set to a value like ansi
, vt320
, or
xterm
. Terminal-based applications use the TERM
variable to
decide what features will be enabled and how they will communicate
with you.
The Telnet client reports its terminal type as ANSI
. This can be
changed by setting the variable TELNET_TERMTYPE
in the MTCP.CFG
file, but it is generally better to keep it as ANSI
. Many
terminal-based applications look at the TERM
variable and expect it
to be set to a standard value like xterm
, vt100
, or ansi
, so you
are generally better off using a standard terminal type like ANSI
.
The ANSI
standard is not well-defined. There are many variants, and
the one that this Telnet uses is its own variant. In order to use all
of the features of this Telnet's ANSI terminal emulation, you need to
create your own "terminfo" file. This package contains the source
code for this "terminfo" file (ansi.src).
On every Linux machine to which you might want to connect (directly
with Telnet or indirectly with ssh), install the ansi
"terminfo"
file and the show script.
You can do this by cloning the GitHub repository with git
and
running ./install.sh
as root. If you don't have git
installed,
you can install it with sudo apt-get install git
.
The install.sh script copies show to /usr/local/bin
, installs
color map PNG files in /usr/local/share/sixel
, and compiles and
installs the ansi
"terminfo" file using tic
.
The show script depends on libsixel-bin
(for img2sixel
),
libimage-size-perl
(for imgsize
), and streamer
(for the --me
)
option. The installation of the ansi
"terminfo" file depends on the
tic
command, which is available in ncurses-bin
.
sudo apt-get install libsixel-bin libimage-size-perl streamer ncurses-bin
git clone https://github.com/jhpyle/mTCP
cd mTCP
sudo ./install.sh
cd ..
The names of these packages and the application for installing
packages (in this example, apt-get
) might be different on your
machines, so you may need to revise this.
If /usr/local/bin
is not part of your PATH
(try echo $PATH
to
see what your PATH
is) you might want to edit the install script so
that it installs the show
script elsewhere.
If you want to install the show script manually, run commands equivalent to the following:
git clone https://github.com/jhpyle/mTCP
sudo install mTCP/sixel/show /usr/local/bin
sudo mkdir -p /usr/local/share/sixel
sudo install -m 644 mTCP/sixel/*.png /usr/local/share/sixel
The show script needs to go into a directory that is in your PATH
.
The PNG files can go in any directory, but if you put them in a
directory other than /usr/local/share/sixel
, make sure you edit the
show script to change the definition of COLORMAPS
so that it
points to the directory you are using.
To install the ansi
"terminfo" file manually, compile the ansi.src
file with tic
:
sudo tic -x -o/etc/terminfo mTCP/ansi.src
Here, /etc/terminfo
is the directory where custom terminfo
description files are installed. It might be located in a different
directory on your system.
This will override the standard terminfo file that is used when the
TERM
environment variable is set to ansi
.
If you do not have administrator access on the machine, you can install the terminfo description for yourself only. You can do this by running:
tic -x mTCP/ansi.src
This will compile the ansi.src file and create the terminfo
description file ~/.terminfo/a/ansi
.
After installing the terminfo file, you can run rm ansi.src
because
you will not need the ansi.src
file any longer (unless you would
like to edit it).
To install the tprint, startprint, and stopprint utilities manually, run commands equivalent to the following:
sudo install mTCP/printing/tprint /usr/local/bin
sudo install mTCP/printing/stopprint /usr/local/bin
sudo install mTCP/printing/startprint /usr/local/bin
The "terminfo" file, on its own, is not sufficient for all of your
Linux applications to work appropriately with the Telnet client. Many
applications look at the TERM
environment variable but bypass the
"terminfo" system. You will need to edit the configuration files of
your applications to get the most out of Telnet.
To improve your bash command line experience, add this to your
~/.inputrc
file:
"\e[7;5~" backward-kill-word
"\e[3;2~" delete-char
"\e[3;5~" kill-word
"\e[5~": beginning-of-history
"\e[6~": end-of-history
If you don't have an ~/.inputrc
file, you can create one with just
these lines in it. This will allow you to type Ctrl-Backspace, Delete,
Ctrl-Delete, Page Up, and Page Down on the command line.
If you use Emacs, download ansi.el.
curl -o ansi.el https://github.com/jhpyle/mTCP/blob/master/ansi.el
Incorporate the contents of this file into your .emacs
file. This
will ensure that Emacs will recognize the control sequences that the
Telnet client will send.
If you are using Vim, add the following to your .vimrc
file:
if &term =~ "ansi"
set mouse=a
endif
However, I was not able to get Vim to respect this setting unless I
set TERM=xterm
, which is not ideal because mTCP's screen-updating
mechanism uses ansi
sequences rather than xterm
sequences.
Modify your .bashrc
to add the following before the part that
references force_color_prompt
:
if [ "$TERM" = "ansi" ]; then
force_color_prompt=yes
fi
If you would prefer a monochrome prompt, leave out
force_color_prompt=yes
.
If you want to toggle printing while using bash using keystrokes,
you can add the following to your .bashrc
file:
bind -x '"\eOP":"echo -n -e \\e[5i"'
bind -x '"\eOQ":"echo -n -e \\e[4i"'
This tells bash that when you press F1, it should send the escape sequence for turning printing on, and when you press F2, it should send the escape sequence for turning printing off.
Add a .mailcap
file to your home directory that contains:
image/*; show %s
This will signal to other applications that the show command should be used to display images.
If you are using Lynx, you can set USE_MOUSE:TRUE
in your
/etc/lynx.cfg
file to enable mouse support.
You can also view images using Sixel graphics while using Lynx.
You can press *
to show links to images, or set
MAKE_LINKS_FOR_ALL_IMAGES:TRUE
in your /etc/lynx.cfg
file to turn
this feature on by default. When you click on a link to an image,
your ~/.mailcap
file will be consulted and the show command will be
used to show the image.
You can also view images while using Links. To set this up, go to
the Setup menu (press Escape to open the menu bar) and go to
Associations. Then you can add file associations for images. The
first "Label" should be, e.g., "PNG," and the "Content-Type" should be
image/png
, and "Program" should be show %
. Unselect "Block
terminal while program running" (this causes problems). Make sure
that "Run on terminal" is selected. Unselect "Ask before opening."
Don't select "Accepts HTTP URLs" or "Accepts FTP URLs." Then save the
Association and repeat the process for image/jpeg
and image/gif
.
Then do "Save options" under "Setup." This will create a file
~/.links2/links.cfg
. The file will contain something like the
following:
association "PNG" "image/png" "show %" 11 1
association "JPEG" "image/jpeg" "show %" 11 1
association "GIF" "image/gif" "show %" 11 1
Image support is a little better in Lynx than it is on Links because it will show a link to an image that is itself a hyperlink.
If you use Midnight Commander, you can edit the file
/usr/lib/mc/ext.d/image.sh
and change this line:
("${MC_XDG_OPEN}" "${MC_EXT_FILENAME}" >/dev/null 2>&1) || \
to:
("${MC_XDG_OPEN}" "${MC_EXT_FILENAME}") || \
Then, if your ~/.mailcap
has been set up as discussed above, the
xdg-open
command will run show
in the terminal when you open an
image file.
If you use R, you might want to use this shorthand for showing a ggplot2 image:
sx <- function(){
ggsave("graph.png", width=3.2, height=2.4)
system("show graph.png")
}
I compiled TELNET.EXE and TELNETNU.EXE using Open Watcom 1.9 inside DosBox on a Linux machine.
I created a folder ~/dos
and installed Watcom under ~/dos/WATCOM
and installed the mTCP source code under ~/dos/MTCP
. I used the default
DosBox configuration (see ~/.dosbox
) with this at the end:
[autoexec]
# Lines in this section will be run at startup.
# You can put your MOUNT lines here.
@echo off
mount c ~/dos
SET PATH=C:\WATCOM\BINW
SET WATCOM=C:\WATCOM
SET INCLUDE=C:\WATCOM\H;C:\MTCP\TCPINC;C:\MTCP\INCLUDE
C:\
CD C:\MTCP\APPS\TELNET
The COMMAND.COM in DosBox limits command lines to 128 characters and there does not appear to be a way to change this. So I had to modify the MAKEFILE by commenting out this line:
compile_options += -i=$(tcp_h_dir) -i=$(common_h_dir)
In its place, I used the INCLUDE
environment variable to let the
compiler know where the .h
files are.
Then I was able to compile Telnet by running wmake
from the
~/dos/MTCP/APPS/TELNET
directory.
I created a batch file called MAKE.BAT
to recompile only the parts I was editing:
del telnet.exe
del telnet.obj
del telnetsc.obj
del telnetsx.obj
del telnet.map
del misc.obj
wmake telnet.exe config=UTF.H
This is much faster than waiting for a full wmake
to complete.
To build a version of telnet.exe
without the Unicode translation feature
support, use the NOUTF.H
file instead of UTF.H
.
For a final build, run wmake
and then wmake patch
, and generate
both TELNETNU.EXE
and TELNET.EXE
. (See the file MAKEALL.BAT
.)