Retire MINIX telnet(1)
..which, for some strange reason, was installed as "ttn". Change-Id: I5ad2f969ad7978a27fb7345f8434470ca427d429
This commit is contained in:
parent
34a8cf369f
commit
4d04ccc15b
@ -547,7 +547,7 @@
|
||||
./usr/bin/true minix-base
|
||||
./usr/bin/truncate minix-base
|
||||
./usr/bin/tsort minix-base
|
||||
./usr/bin/ttn minix-base
|
||||
./usr/bin/ttn minix-base obsolete
|
||||
./usr/bin/tty minix-base
|
||||
./usr/bin/udpstat minix-base obsolete
|
||||
./usr/bin/ul minix-base
|
||||
|
@ -437,7 +437,7 @@
|
||||
./usr/libdata/debug/usr/bin/trace.debug minix-debug debug
|
||||
./usr/libdata/debug/usr/bin/truncate.debug minix-debug debug
|
||||
./usr/libdata/debug/usr/bin/tsort.debug minix-debug debug
|
||||
./usr/libdata/debug/usr/bin/ttn.debug minix-debug debug
|
||||
./usr/libdata/debug/usr/bin/ttn.debug minix-debug debug,obsolete
|
||||
./usr/libdata/debug/usr/bin/tty.debug minix-debug debug
|
||||
./usr/libdata/debug/usr/bin/udpstat.debug minix-debug debug,obsolete
|
||||
./usr/libdata/debug/usr/bin/ul.debug minix-debug debug
|
||||
|
@ -365,7 +365,7 @@
|
||||
./usr/man/man1/tail.1 minix-man
|
||||
./usr/man/man1/tar.1 minix-man
|
||||
./usr/man/man1/tee.1 minix-man
|
||||
./usr/man/man1/telnet.1 minix-man
|
||||
./usr/man/man1/telnet.1 minix-man obsolete
|
||||
./usr/man/man1/template.1 minix-man obsolete
|
||||
./usr/man/man1/term.1 minix-man
|
||||
./usr/man/man1/termcap.1 minix-man
|
||||
|
@ -23,7 +23,6 @@ SUBDIR= at backup \
|
||||
rotate setup \
|
||||
slip spell sprofalyze sprofdiff srccrc \
|
||||
svrctl swifi synctree sysenv \
|
||||
telnet \
|
||||
telnetd term termcap tget \
|
||||
truncate umount \
|
||||
update version vol \
|
||||
|
@ -1,7 +0,0 @@
|
||||
# Makefile for telnet
|
||||
|
||||
PROG= ttn
|
||||
SRCS= ttn.c ttn_conf.c
|
||||
MAN= telnet.1
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,587 +0,0 @@
|
||||
.\" Copyright (c) 1983 Regents of the University of California.
|
||||
.\" All rights reserved. The Berkeley software License Agreement
|
||||
.\" specifies the terms and conditions for redistribution.
|
||||
.\"
|
||||
.\" @(#)telnet.1c 6.5 (Berkeley) 5/10/86
|
||||
.\"
|
||||
.TH TELNET 1 "May 10, 1986"
|
||||
.UC 5
|
||||
.SH NAME
|
||||
telnet \- user interface to the \s-1TELNET\s0 protocol
|
||||
.SH SYNOPSIS
|
||||
telnet [
|
||||
.I host
|
||||
[
|
||||
.I port
|
||||
] ]
|
||||
.SH DESCRIPTION
|
||||
.I Telnet
|
||||
is used to communicate with another host using the
|
||||
.B TELNET
|
||||
protocol.
|
||||
If
|
||||
.I telnet
|
||||
is invoked without arguments, it enters command mode,
|
||||
indicated by its prompt (\*(lqtelnet>\*(rq).
|
||||
In this mode, it accepts and executes the commands listed below.
|
||||
If it is invoked with arguments, it performs an
|
||||
.B open
|
||||
command (see below) with those arguments.
|
||||
.PP
|
||||
Once a connection has been opened,
|
||||
.I telnet
|
||||
enters an input mode.
|
||||
The input mode entered will be either \*(lqcharacter at a time\*(rq
|
||||
or \*(lqline by line\*(rq
|
||||
depending on what the remote system supports.
|
||||
.PP
|
||||
In \*(lqcharacter at a time\*(rq mode, most
|
||||
text typed is immediately sent to the remote host for processing.
|
||||
.PP
|
||||
In \*(lqline by line\*(rq mode, all text is echoed locally,
|
||||
and (normally) only completed lines are sent to the remote host.
|
||||
The \*(lqlocal echo character\*(rq (initially \*(lq^E\*(rq) may be used
|
||||
to turn off and on the local echo
|
||||
(this would mostly be used to enter passwords
|
||||
without the password being echoed).
|
||||
.PP
|
||||
In either mode, if the
|
||||
.I localchars
|
||||
toggle is TRUE (the default in line mode; see below),
|
||||
the user's
|
||||
.IR quit ,
|
||||
.IR intr ,
|
||||
and
|
||||
.I flush
|
||||
characters are trapped locally, and sent as
|
||||
.B TELNET
|
||||
protocol sequences to the remote side.
|
||||
There are options (see
|
||||
.B toggle
|
||||
.I autoflush
|
||||
and
|
||||
.B toggle
|
||||
.I autosynch
|
||||
below)
|
||||
which cause this action to flush subsequent output to the terminal
|
||||
(until the remote host acknowledges the
|
||||
.B TELNET
|
||||
sequence) and flush previous terminal input
|
||||
(in the case of
|
||||
.I quit
|
||||
and
|
||||
.IR intr ).
|
||||
.PP
|
||||
While connected to a remote host,
|
||||
.I telnet
|
||||
command mode may be entered by typing the
|
||||
.I telnet
|
||||
\*(lqescape character\*(rq (initially \*(lq^]\*(rq).
|
||||
When in command mode, the normal terminal editing conventions are available.
|
||||
.PP
|
||||
.B COMMANDS
|
||||
.PP
|
||||
The following commands are available.
|
||||
Only enough of each command to uniquely identify it need be typed
|
||||
(this is also true for arguments to the
|
||||
.BR mode ,
|
||||
.BR set ,
|
||||
.BR toggle ,
|
||||
and
|
||||
.B display
|
||||
commands).
|
||||
.PP
|
||||
.TP
|
||||
.B open \fIhost\fP \fR[\fP \fIport\fP \fR]\fP
|
||||
.br
|
||||
Open a connection to the named host.
|
||||
If no port number
|
||||
is specified,
|
||||
.I telnet
|
||||
will attempt to contact a
|
||||
.B TELNET
|
||||
server at the default port.
|
||||
The host specification may be either a host name (see
|
||||
.IR hosts (5))
|
||||
or an Internet address specified in the \*(lqdot notation\*(rq (see
|
||||
.IR inet (3N)).
|
||||
.TP
|
||||
.B close
|
||||
.br
|
||||
Close a
|
||||
.B TELNET
|
||||
session and return to command mode.
|
||||
.TP
|
||||
.B quit
|
||||
.br
|
||||
Close any open
|
||||
.B TELNET
|
||||
session and exit
|
||||
.IR telnet .
|
||||
An end of file (in command mode) will also close a session and exit.
|
||||
.TP
|
||||
.B z
|
||||
.br
|
||||
Suspend
|
||||
.IR telnet .
|
||||
This command only works when the user is using the
|
||||
.IR csh (1).
|
||||
.TP
|
||||
.B mode \fItype\fP
|
||||
.br
|
||||
.I Type
|
||||
is either
|
||||
.I line
|
||||
(for \*(lqline by line\*(rq mode)
|
||||
or
|
||||
.I character
|
||||
(for \*(lqcharacter at a time\*(rq mode).
|
||||
The remote host is asked for permission to go into the requested mode.
|
||||
If the remote host is capable of entering that mode, the requested
|
||||
mode will be entered.
|
||||
.TP
|
||||
.B status
|
||||
.br
|
||||
Show the current status of
|
||||
.IR telnet .
|
||||
This includes the peer one is connected to, as well
|
||||
as the current mode.
|
||||
.TP
|
||||
.B display \fR[\fP \fIargument...\fP \fR]\fP
|
||||
.br
|
||||
Displays all, or some, of the
|
||||
.B set
|
||||
and
|
||||
.B toggle
|
||||
values (see below).
|
||||
.TP
|
||||
.B ? \fR[\fP \fIcommand\fP \fR]\fP
|
||||
.br
|
||||
Get help. With no arguments,
|
||||
.I telnet
|
||||
prints a help summary.
|
||||
If a command is specified,
|
||||
.I telnet
|
||||
will print the help information for just that command.
|
||||
.TP
|
||||
.B send \fIarguments\fP
|
||||
.br
|
||||
Sends one or more special character sequences to the remote host.
|
||||
The following are the arguments which may be specified
|
||||
(more than one argument may be specified at a time):
|
||||
.RS
|
||||
.TP
|
||||
.I escape
|
||||
.br
|
||||
Sends the current
|
||||
.I telnet
|
||||
escape character (initially \*(lq^]\*(rq).
|
||||
.TP
|
||||
.I synch
|
||||
.br
|
||||
Sends the
|
||||
.B TELNET SYNCH
|
||||
sequence.
|
||||
This sequence causes the remote system to discard all previously typed
|
||||
(but not yet read) input.
|
||||
This sequence is sent as TCP urgent
|
||||
data (and may not work if the remote system is a 4.2 BSD system -- if
|
||||
it doesn't work, a lower case \*(lqr\*(rq may be echoed on the terminal).
|
||||
.TP
|
||||
.I brk
|
||||
.br
|
||||
Sends the
|
||||
.B TELNET BRK
|
||||
(Break) sequence, which may have significance to the remote
|
||||
system.
|
||||
.TP
|
||||
.I ip
|
||||
.br
|
||||
Sends the
|
||||
.B TELNET IP
|
||||
(Interrupt Process) sequence, which should cause the remote
|
||||
system to abort the currently running process.
|
||||
.TP
|
||||
.I ao
|
||||
.br
|
||||
Sends the
|
||||
.B TELNET AO
|
||||
(Abort Output) sequence, which should cause the remote system to flush
|
||||
all output
|
||||
.B from
|
||||
the remote system
|
||||
.B to
|
||||
the user's terminal.
|
||||
.TP
|
||||
.I ayt
|
||||
.br
|
||||
Sends the
|
||||
.B TELNET AYT
|
||||
(Are You There)
|
||||
sequence, to which the remote system may or may not choose to respond.
|
||||
.TP
|
||||
.I ec
|
||||
.br
|
||||
Sends the
|
||||
.B TELNET EC
|
||||
(Erase Character)
|
||||
sequence, which should cause the remote system to erase the last character
|
||||
entered.
|
||||
.TP
|
||||
.I el
|
||||
.br
|
||||
Sends the
|
||||
.B TELNET EL
|
||||
(Erase Line)
|
||||
sequence, which should cause the remote system to erase the line currently
|
||||
being entered.
|
||||
.TP
|
||||
.I ga
|
||||
.br
|
||||
Sends the
|
||||
.B TELNET GA
|
||||
(Go Ahead)
|
||||
sequence, which likely has no significance to the remote system.
|
||||
.TP
|
||||
.I nop
|
||||
.br
|
||||
Sends the
|
||||
.B TELNET NOP
|
||||
(No OPeration)
|
||||
sequence.
|
||||
.TP
|
||||
.I ?
|
||||
.br
|
||||
Prints out help information for the
|
||||
.B send
|
||||
command.
|
||||
.RE
|
||||
.TP
|
||||
.B set \fIargument value\fP
|
||||
.br
|
||||
Set any one of a number of
|
||||
.I telnet
|
||||
variables to a specific value.
|
||||
The special value \*(lqoff\*(rq turns off the function associated with
|
||||
the variable.
|
||||
The values of variables may be interrogated with the
|
||||
.B display
|
||||
command.
|
||||
The variables which may be specified are:
|
||||
.RS
|
||||
.TP
|
||||
.I echo
|
||||
.br
|
||||
This is the value (initially \*(lq^E\*(rq) which, when in
|
||||
\*(lqline by line\*(rq mode, toggles between doing local echoing
|
||||
of entered characters (for normal processing), and suppressing
|
||||
echoing of entered characters (for entering, say, a password).
|
||||
.TP
|
||||
.I escape
|
||||
.br
|
||||
This is the
|
||||
.I telnet
|
||||
escape character (initially \*(lq^[\*(rq) which causes entry
|
||||
into
|
||||
.I telnet
|
||||
command mode (when connected to a remote system).
|
||||
.TP
|
||||
.I interrupt
|
||||
.br
|
||||
If
|
||||
.I telnet
|
||||
is in
|
||||
.I localchars
|
||||
mode (see
|
||||
.B toggle
|
||||
.I localchars
|
||||
below)
|
||||
and the
|
||||
.I interrupt
|
||||
character is typed, a
|
||||
.B TELNET IP
|
||||
sequence (see
|
||||
.B send
|
||||
.I ip
|
||||
above)
|
||||
is sent to the remote host.
|
||||
The initial value for the interrupt character is taken to be
|
||||
the terminal's
|
||||
.B intr
|
||||
character.
|
||||
.TP
|
||||
.I quit
|
||||
.br
|
||||
If
|
||||
.I telnet
|
||||
is in
|
||||
.I localchars
|
||||
mode (see
|
||||
.B toggle
|
||||
.I localchars
|
||||
below)
|
||||
and the
|
||||
.I quit
|
||||
character is typed, a
|
||||
.B TELNET BRK
|
||||
sequence (see
|
||||
.B send
|
||||
.I brk
|
||||
above)
|
||||
is sent to the remote host.
|
||||
The initial value for the quit character is taken to be
|
||||
the terminal's
|
||||
.B quit
|
||||
character.
|
||||
.TP
|
||||
.I flushoutput
|
||||
.br
|
||||
If
|
||||
.I telnet
|
||||
is in
|
||||
.I localchars
|
||||
mode (see
|
||||
.B toggle
|
||||
.I localchars
|
||||
below)
|
||||
and the
|
||||
.I flushoutput
|
||||
character is typed, a
|
||||
.B TELNET AO
|
||||
sequence (see
|
||||
.B send
|
||||
.I ao
|
||||
above)
|
||||
is sent to the remote host.
|
||||
The initial value for the flush character is taken to be
|
||||
the terminal's
|
||||
.B flush
|
||||
character.
|
||||
.TP
|
||||
.I erase
|
||||
.br
|
||||
If
|
||||
.I telnet
|
||||
is in
|
||||
.I localchars
|
||||
mode (see
|
||||
.B toggle
|
||||
.I localchars
|
||||
below),
|
||||
.B and
|
||||
if
|
||||
.I telnet
|
||||
is operating in \*(lqcharacter at a time\*(rq mode, then when this
|
||||
character is typed, a
|
||||
.B TELNET EC
|
||||
sequence (see
|
||||
.B send
|
||||
.I ec
|
||||
above)
|
||||
is sent to the remote system.
|
||||
The initial value for the erase character is taken to be
|
||||
the terminal's
|
||||
.B erase
|
||||
character.
|
||||
.TP
|
||||
.I kill
|
||||
.br
|
||||
If
|
||||
.I telnet
|
||||
is in
|
||||
.I localchars
|
||||
mode (see
|
||||
.B toggle
|
||||
.I localchars
|
||||
below),
|
||||
.B and
|
||||
if
|
||||
.I telnet
|
||||
is operating in \*(lqcharacter at a time\*(rq mode, then when this
|
||||
character is typed, a
|
||||
.B TELNET EL
|
||||
sequence (see
|
||||
.B send
|
||||
.I el
|
||||
above)
|
||||
is sent to the remote system.
|
||||
The initial value for the kill character is taken to be
|
||||
the terminal's
|
||||
.B kill
|
||||
character.
|
||||
.TP
|
||||
.I eof
|
||||
.br
|
||||
If
|
||||
.I telnet
|
||||
is operating in \*(lqline by line\*(rq mode, entering this character
|
||||
as the first character on a line will cause this character to be
|
||||
sent to the remote system.
|
||||
The initial value of the eof character is taken to be the terminal's
|
||||
.B eof
|
||||
character.
|
||||
.RE
|
||||
.TP
|
||||
.B toggle \fIarguments...\fP
|
||||
.br
|
||||
Toggle (between
|
||||
TRUE
|
||||
and
|
||||
FALSE)
|
||||
various flags that control how
|
||||
.I telnet
|
||||
responds to events.
|
||||
More than one argument may be specified.
|
||||
The state of these flags may be interrogated with the
|
||||
.B display
|
||||
command.
|
||||
Valid arguments are:
|
||||
.RS
|
||||
.TP
|
||||
.I localchars
|
||||
.br
|
||||
If this is
|
||||
TRUE,
|
||||
then the
|
||||
.IR flush ,
|
||||
.IR interrupt ,
|
||||
.IR quit ,
|
||||
.IR erase ,
|
||||
and
|
||||
.I kill
|
||||
characters (see
|
||||
.B set
|
||||
above) are recognized locally, and transformed into (hopefully) appropriate
|
||||
.B TELNET
|
||||
control sequences
|
||||
(respectively
|
||||
.IR ao ,
|
||||
.IR ip ,
|
||||
.IR brk ,
|
||||
.IR ec ,
|
||||
and
|
||||
.IR el ;
|
||||
see
|
||||
.B send
|
||||
above).
|
||||
The initial value for this toggle is TRUE in \*(lqline by line\*(rq mode,
|
||||
and FALSE in \*(lqcharacter at a time\*(rq mode.
|
||||
.TP
|
||||
.I autoflush
|
||||
.br
|
||||
If
|
||||
.I autoflush
|
||||
and
|
||||
.I localchars
|
||||
are both
|
||||
TRUE,
|
||||
then when the
|
||||
.IR ao ,
|
||||
.IR intr ,
|
||||
or
|
||||
.I quit
|
||||
characters are recognized (and transformed into
|
||||
.B TELNET
|
||||
sequences; see
|
||||
.B set
|
||||
above for details),
|
||||
.I telnet
|
||||
refuses to display any data on the user's terminal
|
||||
until the remote system acknowledges (via a
|
||||
.B TELNET
|
||||
.I Timing Mark
|
||||
option)
|
||||
that it has processed those
|
||||
.B TELNET
|
||||
sequences.
|
||||
The initial value for this toggle is TRUE if the terminal user had not
|
||||
done an "stty noflsh", otherwise FALSE (see
|
||||
.IR stty(1)).
|
||||
.TP
|
||||
.I autosynch
|
||||
If
|
||||
.I autosynch
|
||||
and
|
||||
.I localchars
|
||||
are both
|
||||
TRUE,
|
||||
then when either the
|
||||
.I intr
|
||||
or
|
||||
.I quit
|
||||
characters is typed (see
|
||||
.B set
|
||||
above for descriptions of the
|
||||
.I intr
|
||||
and
|
||||
.I quit
|
||||
characters), the resulting
|
||||
.B TELNET
|
||||
sequence sent is followed by the
|
||||
.B TELNET SYNCH
|
||||
sequence.
|
||||
This procedure
|
||||
.B should
|
||||
cause the remote system to begin throwing away all previously
|
||||
typed input until both of the
|
||||
.B TELNET
|
||||
sequences have been read and acted upon.
|
||||
The initial value of this toggle is FALSE.
|
||||
.TP
|
||||
.I crmod
|
||||
.br
|
||||
Toggle carriage return mode.
|
||||
When this mode is enabled, most carriage return characters received from
|
||||
the remote host will be mapped into a carriage return followed by
|
||||
a line feed.
|
||||
This mode does not affect those characters typed by the user, only
|
||||
those received from the remote host.
|
||||
This mode is not very useful unless the remote host
|
||||
only sends carriage return, but never line feed.
|
||||
The initial value for this toggle is FALSE.
|
||||
.TP
|
||||
.I debug
|
||||
.br
|
||||
Toggles socket level debugging (useful only to the
|
||||
.IR super user ).
|
||||
The initial value for this toggle is FALSE.
|
||||
.TP
|
||||
.I options
|
||||
.br
|
||||
Toggles the display of some internal
|
||||
.I telnet
|
||||
protocol processing (having to do with
|
||||
.B TELNET
|
||||
options).
|
||||
The initial value for this toggle is FALSE.
|
||||
.TP
|
||||
.I netdata
|
||||
.br
|
||||
Toggles the display of all network data (in hexadecimal format).
|
||||
The initial value for this toggle is FALSE.
|
||||
.TP
|
||||
.I ?
|
||||
.br
|
||||
Displays the legal
|
||||
.B toggle
|
||||
commands.
|
||||
.RE
|
||||
.SH BUGS
|
||||
.PP
|
||||
There is no adequate way for dealing with flow control.
|
||||
.PP
|
||||
On some remote systems, echo has to be turned off manually when in
|
||||
\*(lqline by line\*(rq mode.
|
||||
.PP
|
||||
There is enough settable state to justify a
|
||||
.RI . telnetrc
|
||||
file.
|
||||
.PP
|
||||
No capability for a
|
||||
.RI . telnetrc
|
||||
file is provided.
|
||||
.PP
|
||||
In \*(lqline by line\*(rq mode, the terminal's
|
||||
.I eof
|
||||
character is only recognized (and sent to the remote system)
|
||||
when it is the first character on a line.
|
@ -1,686 +0,0 @@
|
||||
/*
|
||||
ttn.c
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <net/hton.h>
|
||||
#include <net/netlib.h>
|
||||
#include <net/gen/in.h>
|
||||
#include <net/gen/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <net/gen/tcp.h>
|
||||
#include <net/gen/tcp_io.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "ttn.h"
|
||||
|
||||
#if __STDC__
|
||||
#define PROTOTYPE(func,args) func args
|
||||
#else
|
||||
#define PROTOTYPE(func,args) func()
|
||||
#endif
|
||||
|
||||
static int do_read(int fd, char *buf, unsigned len);
|
||||
static void screen(void);
|
||||
static void keyboard(void);
|
||||
static void send_brk(void);
|
||||
static int process_opt (char *bp, int count);
|
||||
static void do_option (int optsrt);
|
||||
static void dont_option (int optsrt);
|
||||
static void will_option (int optsrt);
|
||||
static void wont_option (int optsrt);
|
||||
static int writeall (int fd, char *buffer, int buf_size);
|
||||
static int sb_termtype (char *sb, int count);
|
||||
static void fatal(char *fmt, ...);
|
||||
static void usage(void);
|
||||
|
||||
#if DEBUG
|
||||
#define where() (fprintf(stderr, "%s %d:", __FILE__, __LINE__))
|
||||
#endif
|
||||
|
||||
static char *prog_name;
|
||||
static int tcp_fd;
|
||||
static char *term_env;
|
||||
static int esc_char= '~';
|
||||
static enum { LS_NORM, LS_BOL, LS_ESC } line_state= LS_BOL;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct hostent *hostent;
|
||||
struct servent *servent;
|
||||
ipaddr_t host;
|
||||
tcpport_t port;
|
||||
int pid, ppid;
|
||||
nwio_tcpconf_t tcpconf;
|
||||
int c, r;
|
||||
nwio_tcpcl_t tcpconnopt;
|
||||
struct termios termios;
|
||||
char *tcp_device, *remote_name, *port_name;
|
||||
char *e_arg;
|
||||
|
||||
(prog_name=strrchr(argv[0],'/')) ? prog_name++ : (prog_name=argv[0]);
|
||||
|
||||
e_arg= NULL;
|
||||
while (c= getopt(argc, argv, "?e:"), c != -1)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case '?': usage();
|
||||
case 'e': e_arg= optarg; break;
|
||||
default:
|
||||
fatal("Optind failed: '%c'", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
usage();
|
||||
remote_name= argv[optind++];
|
||||
if (optind < argc)
|
||||
port_name= argv[optind++];
|
||||
else
|
||||
port_name= NULL;
|
||||
if (optind != argc)
|
||||
usage();
|
||||
|
||||
if (e_arg)
|
||||
{
|
||||
switch(strlen(e_arg))
|
||||
{
|
||||
case 0: esc_char= -1; break;
|
||||
case 1: esc_char= e_arg[0]; break;
|
||||
default: fatal("Invalid escape character '%s'", e_arg);
|
||||
}
|
||||
}
|
||||
|
||||
hostent= gethostbyname(remote_name);
|
||||
if (!hostent)
|
||||
fatal("Unknown host %s", remote_name);
|
||||
host= *(ipaddr_t *)(hostent->h_addr);
|
||||
|
||||
if (!port_name)
|
||||
port= htons(TCPPORT_TELNET);
|
||||
else
|
||||
{
|
||||
servent= getservbyname (port_name, "tcp");
|
||||
if (!servent)
|
||||
{
|
||||
port= htons(strtol(port_name, (char **)0, 0));
|
||||
if (!port)
|
||||
fatal("Unknown port %s", port_name);
|
||||
}
|
||||
else
|
||||
port= (tcpport_t)(servent->s_port);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Connecting to %s:%u...\n",
|
||||
inet_ntoa(*(struct in_addr *)&host), ntohs(port));
|
||||
|
||||
tcp_device= getenv("TCP_DEVICE");
|
||||
if (tcp_device == NULL)
|
||||
tcp_device= TCP_DEVICE;
|
||||
tcp_fd= open (tcp_device, O_RDWR);
|
||||
if (tcp_fd == -1)
|
||||
fatal("Unable to open %s: %s", tcp_device, strerror(errno));
|
||||
|
||||
tcpconf.nwtc_flags= NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
|
||||
tcpconf.nwtc_remaddr= host;
|
||||
tcpconf.nwtc_remport= port;
|
||||
|
||||
r= ioctl (tcp_fd, NWIOSTCPCONF, &tcpconf);
|
||||
if (r == -1)
|
||||
fatal("NWIOSTCPCONF failed: %s", strerror(errno));
|
||||
|
||||
tcpconnopt.nwtcl_flags= 0;
|
||||
do
|
||||
{
|
||||
r= ioctl (tcp_fd, NWIOTCPCONN, &tcpconnopt);
|
||||
if (r == -1 && errno == EAGAIN)
|
||||
{
|
||||
fprintf(stderr, "%s: Got EAGAIN, sleeping(1s)\n",
|
||||
prog_name);
|
||||
sleep(1);
|
||||
}
|
||||
} while (r == -1 && errno == EAGAIN);
|
||||
if (r == -1)
|
||||
fatal("Unable to connect: %s", strerror(errno));
|
||||
printf("Connected\n");
|
||||
ppid= getpid();
|
||||
pid= fork();
|
||||
switch(pid)
|
||||
{
|
||||
case 0:
|
||||
keyboard();
|
||||
#if DEBUG
|
||||
fprintf(stderr, "killing %d with %d\r\n", ppid, SIGKILL);
|
||||
#endif
|
||||
kill(ppid, SIGKILL);
|
||||
break;
|
||||
case -1:
|
||||
fprintf(stderr, "%s: fork failed: %s\r\n", argv[0],
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
break;
|
||||
default:
|
||||
tcgetattr(0, &termios);
|
||||
screen();
|
||||
#if DEBUG
|
||||
fprintf(stderr, "killing %d with %d\r\n", pid, SIGKILL);
|
||||
#endif
|
||||
kill(pid, SIGKILL);
|
||||
tcsetattr(0, TCSANOW, &termios);
|
||||
break;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int do_read(fd, buf, len)
|
||||
int fd;
|
||||
char *buf;
|
||||
unsigned len;
|
||||
{
|
||||
nwio_tcpopt_t tcpopt;
|
||||
int count;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
count= read (fd, buf, len);
|
||||
if (count <0)
|
||||
{
|
||||
if (errno == EURG || errno == ENOURG)
|
||||
{
|
||||
/* Toggle urgent mode. */
|
||||
tcpopt.nwto_flags= errno == EURG ?
|
||||
NWTO_RCV_URG : NWTO_RCV_NOTURG;
|
||||
if (ioctl(tcp_fd, NWIOSTCPOPT, &tcpopt) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
static void screen()
|
||||
{
|
||||
char buffer[1024], *bp, *iacptr;
|
||||
int count, optsize;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
count= do_read (tcp_fd, buffer, sizeof(buffer));
|
||||
#if DEBUG && 0
|
||||
{ where(); fprintf(stderr, "read %d bytes\r\n", count); }
|
||||
#endif
|
||||
if (count <0)
|
||||
{
|
||||
perror ("read");
|
||||
return;
|
||||
}
|
||||
if (!count)
|
||||
return;
|
||||
bp= buffer;
|
||||
do
|
||||
{
|
||||
iacptr= memchr (bp, IAC, count);
|
||||
if (!iacptr)
|
||||
{
|
||||
write(1, bp, count);
|
||||
count= 0;
|
||||
}
|
||||
if (iacptr && iacptr>bp)
|
||||
{
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "iacptr-bp= %d\r\n", iacptr-bp); }
|
||||
#endif
|
||||
write(1, bp, iacptr-bp);
|
||||
count -= (iacptr-bp);
|
||||
bp= iacptr;
|
||||
continue;
|
||||
}
|
||||
if (iacptr)
|
||||
{
|
||||
assert (iacptr == bp);
|
||||
optsize= process_opt(bp, count);
|
||||
#if DEBUG && 0
|
||||
{ where(); fprintf(stderr, "process_opt(...)= %d\r\n", optsize); }
|
||||
#endif
|
||||
if (optsize<0)
|
||||
return;
|
||||
assert (optsize);
|
||||
bp += optsize;
|
||||
count -= optsize;
|
||||
}
|
||||
} while (count);
|
||||
}
|
||||
}
|
||||
|
||||
static void keyboard()
|
||||
{
|
||||
char c, buffer[1024];
|
||||
int count;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
count= read (0, buffer, 1 /* sizeof(buffer) */);
|
||||
if (count == -1)
|
||||
fatal("Read: %s\r\n", strerror(errno));
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
if (line_state != LS_NORM)
|
||||
{
|
||||
c= buffer[0];
|
||||
if (line_state == LS_BOL)
|
||||
{
|
||||
if (c == esc_char)
|
||||
{
|
||||
line_state= LS_ESC;
|
||||
continue;
|
||||
}
|
||||
line_state= LS_NORM;
|
||||
}
|
||||
else if (line_state == LS_ESC)
|
||||
{
|
||||
line_state= LS_NORM;
|
||||
if (c == '.')
|
||||
return;
|
||||
if (c == '#')
|
||||
{
|
||||
send_brk();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Not a valid command or a repeat of the
|
||||
* escape char
|
||||
*/
|
||||
if (c != esc_char)
|
||||
{
|
||||
c= esc_char;
|
||||
write(tcp_fd, &c, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buffer[0] == '\n')
|
||||
write(tcp_fd, "\r", 1);
|
||||
count= write(tcp_fd, buffer, count);
|
||||
if (buffer[0] == '\r')
|
||||
{
|
||||
line_state= LS_BOL;
|
||||
write(tcp_fd, "\0", 1);
|
||||
}
|
||||
if (count<0)
|
||||
{
|
||||
perror("write");
|
||||
fprintf(stderr, "errno= %d\r\n", errno);
|
||||
return;
|
||||
}
|
||||
if (!count)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void send_brk(void)
|
||||
{
|
||||
int r;
|
||||
unsigned char buffer[2];
|
||||
|
||||
buffer[0]= IAC;
|
||||
buffer[1]= IAC_BRK;
|
||||
|
||||
r= writeall(tcp_fd, (char *)buffer, 2);
|
||||
if (r == -1)
|
||||
fatal("Error writing to TCP connection: %s", strerror(errno));
|
||||
}
|
||||
|
||||
#define next_char(var) \
|
||||
if (offset<count) { (var) = bp[offset++]; } \
|
||||
else if (do_read(tcp_fd, (char *)&(var), 1) <= 0) \
|
||||
{ perror ("read"); return -1; }
|
||||
|
||||
static int process_opt (char *bp, int count)
|
||||
{
|
||||
unsigned char iac, command, optsrt, sb_command;
|
||||
int offset, result; ;
|
||||
#if DEBUG && 0
|
||||
{ where(); fprintf(stderr, "process_opt(bp= 0x%x, count= %d)\r\n",
|
||||
bp, count); }
|
||||
#endif
|
||||
|
||||
offset= 0;
|
||||
assert (count);
|
||||
next_char(iac);
|
||||
assert (iac == IAC);
|
||||
next_char(command);
|
||||
switch(command)
|
||||
{
|
||||
case IAC_NOP:
|
||||
break;
|
||||
case IAC_DataMark:
|
||||
/* Ought to flush input queue or something. */
|
||||
break;
|
||||
case IAC_BRK:
|
||||
fprintf(stderr, "got a BRK\r\n");
|
||||
break;
|
||||
case IAC_IP:
|
||||
fprintf(stderr, "got a IP\r\n");
|
||||
break;
|
||||
case IAC_AO:
|
||||
fprintf(stderr, "got a AO\r\n");
|
||||
break;
|
||||
case IAC_AYT:
|
||||
fprintf(stderr, "got a AYT\r\n");
|
||||
break;
|
||||
case IAC_EC:
|
||||
fprintf(stderr, "got a EC\r\n");
|
||||
break;
|
||||
case IAC_EL:
|
||||
fprintf(stderr, "got a EL\r\n");
|
||||
break;
|
||||
case IAC_GA:
|
||||
fprintf(stderr, "got a GA\r\n");
|
||||
break;
|
||||
case IAC_SB:
|
||||
next_char(sb_command);
|
||||
switch (sb_command)
|
||||
{
|
||||
case OPT_TERMTYPE:
|
||||
#if DEBUG && 0
|
||||
fprintf(stderr, "got SB TERMINAL-TYPE\r\n");
|
||||
#endif
|
||||
result= sb_termtype(bp+offset, count-offset);
|
||||
if (result<0)
|
||||
return result;
|
||||
else
|
||||
return result+offset;
|
||||
default:
|
||||
fprintf(stderr, "got an unknown SB (skiping)\r\n");
|
||||
for (;;)
|
||||
{
|
||||
next_char(iac);
|
||||
if (iac != IAC)
|
||||
continue;
|
||||
next_char(optsrt);
|
||||
if (optsrt == IAC)
|
||||
continue;
|
||||
if (optsrt != IAC_SE)
|
||||
fprintf(stderr, "got IAC %d\r\n", optsrt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IAC_WILL:
|
||||
next_char(optsrt);
|
||||
will_option(optsrt);
|
||||
break;
|
||||
case IAC_WONT:
|
||||
next_char(optsrt);
|
||||
wont_option(optsrt);
|
||||
break;
|
||||
case IAC_DO:
|
||||
next_char(optsrt);
|
||||
do_option(optsrt);
|
||||
break;
|
||||
case IAC_DONT:
|
||||
next_char(optsrt);
|
||||
dont_option(optsrt);
|
||||
break;
|
||||
case IAC:
|
||||
fprintf(stderr, "got a IAC\r\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "got unknown command (%d)\r\n", command);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void do_option (int optsrt)
|
||||
{
|
||||
unsigned char reply[3];
|
||||
int result;
|
||||
|
||||
switch (optsrt)
|
||||
{
|
||||
case OPT_TERMTYPE:
|
||||
if (WILL_terminal_type)
|
||||
return;
|
||||
if (!WILL_terminal_type_allowed)
|
||||
{
|
||||
reply[0]= IAC;
|
||||
reply[1]= IAC_WONT;
|
||||
reply[2]= optsrt;
|
||||
}
|
||||
else
|
||||
{
|
||||
WILL_terminal_type= TRUE;
|
||||
term_env= getenv("TERM");
|
||||
if (!term_env)
|
||||
term_env= "unknown";
|
||||
reply[0]= IAC;
|
||||
reply[1]= IAC_WILL;
|
||||
reply[2]= optsrt;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
#if DEBUG
|
||||
fprintf(stderr, "got a DO (%d)\r\n", optsrt);
|
||||
fprintf(stderr, "WONT (%d)\r\n", optsrt);
|
||||
#endif
|
||||
reply[0]= IAC;
|
||||
reply[1]= IAC_WONT;
|
||||
reply[2]= optsrt;
|
||||
break;
|
||||
}
|
||||
result= writeall(tcp_fd, (char *)reply, 3);
|
||||
if (result<0)
|
||||
perror("write");
|
||||
}
|
||||
|
||||
static void will_option (int optsrt)
|
||||
{
|
||||
unsigned char reply[3];
|
||||
int result;
|
||||
|
||||
switch (optsrt)
|
||||
{
|
||||
case OPT_ECHO:
|
||||
if (DO_echo)
|
||||
break;
|
||||
if (!DO_echo_allowed)
|
||||
{
|
||||
reply[0]= IAC;
|
||||
reply[1]= IAC_DONT;
|
||||
reply[2]= optsrt;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct termios termios;
|
||||
|
||||
tcgetattr(0, &termios);
|
||||
termios.c_iflag &= ~(ICRNL|IGNCR|INLCR|IXON|IXOFF);
|
||||
termios.c_oflag &= ~(OPOST);
|
||||
termios.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
|
||||
tcsetattr(0, TCSANOW, &termios);
|
||||
|
||||
DO_echo= TRUE;
|
||||
reply[0]= IAC;
|
||||
reply[1]= IAC_DO;
|
||||
reply[2]= optsrt;
|
||||
}
|
||||
result= writeall(tcp_fd, (char *)reply, 3);
|
||||
if (result<0)
|
||||
perror("write");
|
||||
break;
|
||||
case OPT_SUPP_GA:
|
||||
if (DO_suppress_go_ahead)
|
||||
break;
|
||||
if (!DO_suppress_go_ahead_allowed)
|
||||
{
|
||||
reply[0]= IAC;
|
||||
reply[1]= IAC_DONT;
|
||||
reply[2]= optsrt;
|
||||
}
|
||||
else
|
||||
{
|
||||
DO_suppress_go_ahead= TRUE;
|
||||
reply[0]= IAC;
|
||||
reply[1]= IAC_DO;
|
||||
reply[2]= optsrt;
|
||||
}
|
||||
result= writeall(tcp_fd, (char *)reply, 3);
|
||||
if (result<0)
|
||||
perror("write");
|
||||
break;
|
||||
default:
|
||||
#if DEBUG
|
||||
fprintf(stderr, "got a WILL (%d)\r\n", optsrt);
|
||||
fprintf(stderr, "DONT (%d)\r\n", optsrt);
|
||||
#endif
|
||||
reply[0]= IAC;
|
||||
reply[1]= IAC_DONT;
|
||||
reply[2]= optsrt;
|
||||
result= writeall(tcp_fd, (char *)reply, 3);
|
||||
if (result<0)
|
||||
perror("write");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int writeall (fd, buffer, buf_size)
|
||||
int fd;
|
||||
char *buffer;
|
||||
int buf_size;
|
||||
{
|
||||
int result;
|
||||
|
||||
while (buf_size)
|
||||
{
|
||||
result= write (fd, buffer, buf_size);
|
||||
if (result <= 0)
|
||||
return -1;
|
||||
assert (result <= buf_size);
|
||||
buffer += result;
|
||||
buf_size -= result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dont_option (int optsrt)
|
||||
{
|
||||
switch (optsrt)
|
||||
{
|
||||
default:
|
||||
#if DEBUG
|
||||
fprintf(stderr, "got a DONT (%d)\r\n", optsrt);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void wont_option (int optsrt)
|
||||
{
|
||||
switch (optsrt)
|
||||
{
|
||||
default:
|
||||
#if DEBUG
|
||||
fprintf(stderr, "got a WONT (%d)\r\n", optsrt);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int sb_termtype (char *bp, int count)
|
||||
{
|
||||
unsigned char command, iac, optsrt;
|
||||
unsigned char buffer[4];
|
||||
int offset, result;
|
||||
|
||||
offset= 0;
|
||||
next_char(command);
|
||||
if (command == TERMTYPE_SEND)
|
||||
{
|
||||
buffer[0]= IAC;
|
||||
buffer[1]= IAC_SB;
|
||||
buffer[2]= OPT_TERMTYPE;
|
||||
buffer[3]= TERMTYPE_IS;
|
||||
result= writeall(tcp_fd, (char *)buffer,4);
|
||||
if (result<0)
|
||||
return result;
|
||||
count= strlen(term_env);
|
||||
if (!count)
|
||||
{
|
||||
term_env= "unknown";
|
||||
count= strlen(term_env);
|
||||
}
|
||||
result= writeall(tcp_fd, term_env, count);
|
||||
if (result<0)
|
||||
return result;
|
||||
buffer[0]= IAC;
|
||||
buffer[1]= IAC_SE;
|
||||
result= writeall(tcp_fd, (char *)buffer,2);
|
||||
if (result<0)
|
||||
return result;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
where();
|
||||
#endif
|
||||
fprintf(stderr, "got an unknown command (skipping)\r\n");
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
next_char(iac);
|
||||
if (iac != IAC)
|
||||
continue;
|
||||
next_char(optsrt);
|
||||
if (optsrt == IAC)
|
||||
continue;
|
||||
if (optsrt != IAC_SE)
|
||||
{
|
||||
#if DEBUG
|
||||
where();
|
||||
#endif
|
||||
fprintf(stderr, "got IAC %d\r\n", optsrt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void fatal(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "%s: ", prog_name);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-e esc-char] host [port]\r\n",
|
||||
prog_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: ttn.c,v 1.5 2002/05/07 12:06:41 philip Exp $
|
||||
*/
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
ttn.h
|
||||
*/
|
||||
|
||||
#ifndef TTN_H
|
||||
#define TTN_H
|
||||
|
||||
#define IAC 255
|
||||
#define IAC_SE 240
|
||||
#define IAC_NOP 241
|
||||
#define IAC_DataMark 242
|
||||
#define IAC_BRK 243
|
||||
#define IAC_IP 244
|
||||
#define IAC_AO 245
|
||||
#define IAC_AYT 246
|
||||
#define IAC_EC 247
|
||||
#define IAC_EL 248
|
||||
#define IAC_GA 249
|
||||
#define IAC_SB 250
|
||||
#define IAC_WILL 251
|
||||
#define IAC_WONT 252
|
||||
#define IAC_DO 253
|
||||
#define IAC_DONT 254
|
||||
|
||||
#define OPT_ECHO 1
|
||||
#define OPT_SUPP_GA 3
|
||||
#define OPT_TERMTYPE 24
|
||||
|
||||
#define TERMTYPE_SEND 1
|
||||
#define TERMTYPE_IS 0
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE (!(FALSE))
|
||||
|
||||
extern int DO_echo;
|
||||
extern int DO_echo_allowed;
|
||||
extern int WILL_terminal_type;
|
||||
extern int WILL_terminal_type_allowed;
|
||||
extern int DO_suppress_go_ahead;
|
||||
extern int DO_suppress_go_ahead_allowed;
|
||||
extern int WILL_suppress_go_ahead;
|
||||
extern int WILL_suppress_go_ahead_allowed;
|
||||
|
||||
#endif /* TTN_H */
|
@ -1,12 +0,0 @@
|
||||
/*
|
||||
ttn_conf.c
|
||||
*/
|
||||
|
||||
#include "ttn.h"
|
||||
|
||||
int DO_echo= FALSE;
|
||||
int DO_echo_allowed= TRUE;
|
||||
int WILL_terminal_type= FALSE;
|
||||
int WILL_terminal_type_allowed= TRUE;
|
||||
int DO_suppress_go_ahead= FALSE;
|
||||
int DO_suppress_go_ahead_allowed= TRUE;
|
Loading…
x
Reference in New Issue
Block a user