* Copyright (c) 1988 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
static char sccsid
[] = "@(#)commands.c 1.4 (Berkeley) %G%";
#define Ambiguous(s) ((char *)s == ambiguous)
static char *ambiguous
; /* special return value for command routines */
char *name
; /* command name */
char *help
; /* help string */
int (*handler
)(); /* routine which executes command */
int dohelp
; /* Should we give general help information? */
int needconnect
; /* Do we need to be connected to execute? */
* Various utility routines.
register char **argp
= margv
;
if (*cp
== '!') { /* Special case shell escape */
*argp
++ = "!"; /* No room in string to get this */
while (*cp
!= '\0' && !isspace(*cp
))
genget(name
, table
, next
)
char *name
; /* name to match */
char **table
; /* name entry in table */
char **(*next
)(); /* routine to return next entry in table */
register char **c
, **found
;
register int nmatches
, longest
;
for (c
= table
; (p
= *c
) != 0; c
= (*next
)(c
)) {
(*q
== *p
) || (isupper(*q
) && tolower(*q
) == *p
); p
++, q
++)
if (*q
== 0) /* exact match? */
if (!*q
) { /* the name was a prefix */
if (q
- name
> longest
) {
} else if (q
- name
== longest
)
return (char **)ambiguous
;
* Make a character string into a number.
* Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
* Construct a control character sequence
* for a special character.
* The following are data structures and routines for
char *name
; /* How user refers to it (case independent) */
int what
; /* Character to be sent (<0 ==> special) */
char *help
; /* Help information (0 ==> no help) */
int (*routine
)(); /* Routine to perform (for special ops) */
#else /* defined(NOT43) */
void (*routine
)(); /* Routine to perform (for special ops) */
#endif /* defined(NOT43) */
static struct sendlist Sendlist
[] = {
{ "ao", AO
, "Send Telnet Abort output" },
{ "ayt", AYT
, "Send Telnet 'Are You There'" },
{ "brk", BREAK
, "Send Telnet Break" },
{ "ec", EC
, "Send Telnet Erase Character" },
{ "el", EL
, "Send Telnet Erase Line" },
{ "escape", SENDESCAPE
, "Send current escape character" },
{ "ga", GA
, "Send Telnet 'Go Ahead' sequence" },
{ "ip", IP
, "Send Telnet Interrupt Process" },
{ "nop", NOP
, "Send Telnet 'No operation'" },
{ "synch", SYNCH
, "Perform Telnet 'Synch operation'", dosynch
},
{ "?", SENDQUESTION
, "Display send options" },
static struct sendlist Sendlist2
[] = { /* some synonyms */
{ "help", SENDQUESTION
, 0 },
struct sendlist
*c
= (struct sendlist
*) name
;
if ((sl
= (struct sendlist
*)
genget(name
, (char **) Sendlist
, getnextsend
)) != 0) {
return (struct sendlist
*)
genget(name
, (char **) Sendlist2
, getnextsend
);
int what
; /* what we are sending this time */
int count
; /* how many bytes we are going to need to send */
int question
= 0; /* was at least one argument a question */
struct sendlist
*s
; /* pointer to current command */
printf("need at least one argument for 'send' command\n");
printf("'send ?' for help\n");
* First, validate all the send arguments.
* In addition, we see how much space we are going to need, and
* whether or not we will be doing a "SYNCH" operation (which
* flushes the network queue).
for (i
= 1; i
< argc
; i
++) {
printf("Unknown send argument '%s'\n'send ?' for help.\n",
} else if (Ambiguous(s
)) {
printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
/* Now, do we have enough room? */
printf("There is not enough room in the buffer TO the network\n");
printf("to process your request. Nothing will be done.\n");
printf("('send synch' will throw away most data in the network\n");
printf("buffer, if this might help.)\n");
/* OK, they are all OK, now go through again and actually send */
for (i
= 1; i
< argc
; i
++) {
if ((s
= getsend(argv
[i
])) == 0) {
fprintf(stderr
, "Telnet 'send' error - argument disappeared!\n");
switch (what
= s
->what
) {
for (s
= Sendlist
; s
->name
; s
++) {
* The following are the routines and data structures referred
* to by the arguments to the "toggle" command.
(SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, debug
)) < 0) {
perror("setsockopt (SO_DEBUG)");
if (net
> 0 && SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, 0, 0) < 0)
perror("setsockopt (SO_DEBUG)");
printf("Cannot turn off socket debugging\n");
printf("Will send carriage returns as telnet <CR><LF>.\n");
printf("Will send carriage returns as telnet <CR><NUL>.\n");
if (myopts
[TELOPT_BINARY
] == 0) { /* Go into binary mode */
printoption("<SENT", doopt
, TELOPT_BINARY
, 0);
printoption("<SENT", doopt
, TELOPT_BINARY
, 0);
hisopts
[TELOPT_BINARY
] = myopts
[TELOPT_BINARY
] = 1;
printf("Negotiating binary mode with remote host.\n");
} else { /* Turn off binary mode */
printoption("<SENT", dont
, TELOPT_BINARY
, 0);
printoption("<SENT", dont
, TELOPT_BINARY
, 0);
hisopts
[TELOPT_BINARY
] = myopts
[TELOPT_BINARY
] = 0;
printf("Negotiating network ascii mode with remote host.\n");
char *name
; /* name of toggle */
char *help
; /* help message */
int (*handler
)(); /* routine to do actual setting */
int dohelp
; /* should we display help information */
static struct togglelist Togglelist
[] = {
"toggle flushing of output when sending interrupt characters",
"flush output when sending interrupt characters" },
"toggle automatic sending of interrupt characters in urgent mode",
"send interrupt characters in urgent mode" },
"toggle sending and receiving of binary data",
"toggle sending carriage returns as telnet <CR><LF>",
"toggle mapping of received carriage returns",
"map carriage return on output" },
"toggle local recognition of certain control characters",
"recognize certain control characters" },
{ " ", "", 0, 1 }, /* empty line */
"(debugging) toggle debugging",
"turn on socket level debugging" },
"(debugging) toggle printing of hexadecimal network data",
"print hexadecimal representation of network traffic" },
"(debugging) toggle viewing of options processing",
"show option processing" },
{ " ", "", 0, 1 }, /* empty line */
"display help information",
"display help information",
for (c
= Togglelist
; c
->name
; c
++) {
printf("%s\t%s\n", c
->name
, c
->help
);
struct togglelist
*c
= (struct togglelist
*) name
;
static struct togglelist
*
return (struct togglelist
*)
genget(name
, (char **) Togglelist
, getnexttoggle
);
"Need an argument to 'toggle' command. 'toggle ?' for help.\n");
fprintf(stderr
, "'%s': ambiguous argument ('toggle ?' for help).\n",
fprintf(stderr
, "'%s': unknown argument ('toggle ?' for help).\n",
*c
->variable
= !*c
->variable
; /* invert it */
if (c
->actionexplanation
) {
printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
retval
&= (*c
->handler
)(c
);
* The following perform the "set" command.
char *help
; /* help information */
char *charp
; /* where it is located at */
static struct setlist Setlist
[] = {
{ "echo", "character to toggle local echoing on/off", &echoc
},
{ "escape", "character to escape back to telnet command mode", &escape
},
{ " ", "The following need 'localchars' to be toggled true", 0 },
{ "erase", "character to cause an Erase Character", &termEraseChar
},
{ "flushoutput", "character to cause an Abort Oubput", &termFlushChar
},
{ "interrupt", "character to cause an Interrupt Process", &termIntChar
},
{ "kill", "character to cause an Erase Line", &termKillChar
},
{ "quit", "character to cause a Break", &termQuitChar
},
{ "eof", "character to cause an EOF ", &termEofChar
},
struct setlist
*c
= (struct setlist
*)name
;
return (struct setlist
*) genget(name
, (char **) Setlist
, getnextset
);
/* XXX back we go... sigh */
((!strcmp(argv
[1], "?")) || (!strcmp(argv
[1], "help")))) {
for (ct
= Setlist
; ct
->name
; ct
++) {
printf("%s\t%s\n", ct
->name
, ct
->help
);
printf("?\tdisplay help information\n");
printf("Format is 'set Name Value'\n'set ?' for help.\n");
fprintf(stderr
, "'%s': unknown argument ('set ?' for help).\n",
} else if (Ambiguous(ct
)) {
fprintf(stderr
, "'%s': ambiguous argument ('set ?' for help).\n",
if (strcmp("off", argv
[2])) {
value
= special(argv
[2]);
printf("%s character is '%s'.\n", ct
->name
, control(*(ct
->charp
)));
* The following are the data structures and routines for the
if (hisopts
[TELOPT_SGA
]) {
wontoption(TELOPT_SGA
, 0);
if (hisopts
[TELOPT_ECHO
]) {
wontoption(TELOPT_ECHO
, 0);
if (!hisopts
[TELOPT_SGA
]) {
willoption(TELOPT_SGA
, 0);
if (!hisopts
[TELOPT_ECHO
]) {
willoption(TELOPT_ECHO
, 0);
static Command Mode_commands
[] = {
{ "character", "character-at-a-time mode", docharmode
, 1, 1 },
{ "line", "line-by-line mode", dolinemode
, 1, 1 },
Command
*c
= (Command
*) name
;
return (Command
*) genget(name
, (char **) Mode_commands
, getnextmode
);
if ((argc
!= 2) || !strcmp(argv
[1], "?") || !strcmp(argv
[1], "help")) {
printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
for (mt
= Mode_commands
; mt
->name
; mt
++) {
printf("%s\t%s\n", mt
->name
, mt
->help
);
mt
= getmodecmd(argv
[1]);
fprintf(stderr
, "Unknown mode '%s' ('mode ?' for help).\n", argv
[1]);
} else if (Ambiguous(mt
)) {
fprintf(stderr
, "Ambiguous mode '%s' ('mode ?' for help).\n", argv
[1]);
* The following data structures and routines implement the
#define dotog(tl) if (tl->variable && tl->actionexplanation) { \
printf(" %s.\n", tl->actionexplanation); \
#define doset(sl) if (sl->name && *sl->name != ' ') { \
printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
for (tl
= Togglelist
; tl
->name
; tl
++) {
for (sl
= Setlist
; sl
->name
; sl
++) {
for (i
= 1; i
< argc
; i
++) {
if (Ambiguous(sl
) || Ambiguous(tl
)) {
printf("?Ambiguous argument '%s'.\n", argv
[i
]);
printf("?Unknown argument '%s'.\n", argv
[i
]);
* The following are the data structures, and many of the routines,
* relating to command processing.
* Set the escape character.
"Deprecated usage - please use 'set escape%s%s' in the future.\n",
(argc
> 2)? " ":"", (argc
> 2)? argv
[1]: "");
printf("new escape character: ");
printf("Escape character is '%s'.\n", control(escape
));
printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
printf("%s map carriage return on output.\n", crmod
? "Will" : "Won't");
#endif /* defined(unix) */
/* reget parameters in case they were changed */
int argc
; /* Number of arguments */
char *argv
[]; /* arguments */
printf("Connection closed.\n");
SetIn3270(); /* Get out of 3270 mode */
#endif /* defined(TN3270) */
if ((argc
!= 2) || (strcmp(argv
[1], "fromquit") != 0)) {
return 1; /* Keep lint, etc., happy */
(void) call(bye
, "bye", "fromquit", 0);
return 1; /* just to keep lint happy */
* Print status about the connection.
printf("Connected to %s.\n", hostname
);
printf("Operating in %s.\n",
modelist
[getconnmode()].modedescriptions
);
printf("Catching signals locally.\n");
printf("No connection.\n");
printf("Escape character is '%s'.\n", control(escape
));
# else /* !defined(TN3270) */
if ((!In3270
) && ((argc
< 2) || strcmp(argv
[1], "notmuch"))) {
printf("Escape character is '%s'.\n", control(escape
));
if (In3270
&& transcom
) {
printf("Transparent mode command is '%s'.\n", transcom
);
# endif /* defined(unix) */
# endif /* defined(TN3270) */
register struct hostent
*host
= 0;
static char hnamebuf
[32];
#endif /* defined(MSDOS) */
printf("?Already connected to %s\n", hostname
);
(void) strcpy(line
, "Connect ");
gets(&line
[strlen(line
)]);
if ((argc
< 2) || (argc
> 3)) {
printf("usage: %s host-name [port]\n", argv
[0]);
for (cp
= argv
[1]; *cp
; cp
++) {
#endif /* defined(MSDOS) */
sin
.sin_addr
.s_addr
= inet_addr(argv
[1]);
if (sin
.sin_addr
.s_addr
!= -1) {
sin
.sin_family
= AF_INET
;
(void) strcpy(hnamebuf
, argv
[1]);
host
= gethostbyname(argv
[1]);
sin
.sin_family
= host
->h_addrtype
;
#if defined(h_addr) /* In 4.3, this is a #define */
memcpy((caddr_t
)&sin
.sin_addr
,
host
->h_addr_list
[0], host
->h_length
);
#else /* defined(h_addr) */
memcpy((caddr_t
)&sin
.sin_addr
, host
->h_addr
, host
->h_length
);
#endif /* defined(h_addr) */
printf("%s: unknown host\n", argv
[1]);
sin
.sin_port
= atoi(argv
[2]);
sp
= getservbyname(argv
[2], "tcp");
sin
.sin_port
= sp
->s_port
;
printf("%s: bad port number\n", argv
[2]);
sin
.sin_port
= atoi(argv
[2]);
sin
.sin_port
= htons(sin
.sin_port
);
sp
= getservbyname("telnet", "tcp");
fprintf(stderr
, "telnet: tcp/telnet: unknown service\n",1);
sin
.sin_port
= sp
->s_port
;
net
= socket(AF_INET
, SOCK_STREAM
, 0);
perror("telnet: socket");
if (debug
&& SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, 1) < 0) {
perror("setsockopt (SO_DEBUG)");
if (connect(net
, (struct sockaddr
*)&sin
, sizeof (sin
)) < 0) {
#if defined(h_addr) /* In 4.3, this is a #define */
if (host
&& host
->h_addr_list
[1]) {
fprintf(stderr
, "telnet: connect to address %s: ",
inet_ntoa(sin
.sin_addr
));
memcpy((caddr_t
)&sin
.sin_addr
,
host
->h_addr_list
[0], host
->h_length
);
fprintf(stderr
, "Trying %s...\n",
inet_ntoa(sin
.sin_addr
));
#endif /* defined(h_addr) */
perror("telnet: Unable to connect to remote host");
} while (connected
== 0);
call(status
, "status", "notmuch", 0);
if (setjmp(peerdied
) == 0)
ExitString("Connection closed by foreign host.\n",1);
#define HELPINDENT (sizeof ("connect"))
openhelp
[] = "connect to a site",
closehelp
[] = "close current connection",
quithelp
[] = "exit telnet",
statushelp
[] = "print status information",
helphelp
[] = "print help information",
sendhelp
[] = "transmit special characters ('send ?' for more)",
sethelp
[] = "set operating parameters ('set ?' for more)",
togglestring
[] ="toggle operating parameters ('toggle ?' for more)",
displayhelp
[] = "display operating parameters",
#if defined(TN3270) && defined(unix)
transcomhelp
[] = "specify Unix command for transparent mode pipe",
#endif /* defined(TN3270) && defined(unix) */
zhelp
[] = "suspend telnet",
#endif /* defined(unix */
shellhelp
[] = "invoke a subshell",
#endif /* defined(TN3270) */
modehelp
[] = "try to enter line-by-line or character-at-a-time mode";
extern int help(), shell();
static Command cmdtab
[] = {
{ "close", closehelp
, bye
, 1, 1 },
{ "display", displayhelp
, display
, 1, 0 },
{ "mode", modehelp
, modecmd
, 1, 1 },
{ "open", openhelp
, tn
, 1, 0 },
{ "quit", quithelp
, quit
, 1, 0 },
{ "send", sendhelp
, sendcmd
, 1, 1 },
{ "set", sethelp
, setcmd
, 1, 0 },
{ "status", statushelp
, status
, 1, 0 },
{ "toggle", togglestring
, toggle
, 1, 0 },
#if defined(TN3270) && defined(unix)
{ "transcom", transcomhelp
, settranscom
, 1, 0 },
#endif /* defined(TN3270) && defined(unix) */
{ "z", zhelp
, suspend
, 1, 0 },
#endif /* defined(unix) */
{ "!", shellhelp
, shell
, 1, 1 },
#endif /* defined(TN3270) */
{ "?", helphelp
, help
, 1, 0 },
static char crmodhelp
[] = "deprecated command -- use 'toggle crmod' instead";
static char escapehelp
[] = "deprecated command -- use 'set escape' instead";
static Command cmdtab2
[] = {
{ "help", helphelp
, help
, 0, 0 },
{ "escape", escapehelp
, setescape
, 1, 0 },
{ "crmod", crmodhelp
, togcrmod
, 1, 0 },
* Call routine with argc, argv set from args (terminated by 0).
for (argc
= 0, argp
= &args
; *argp
++ != 0; argc
++)
return (*routine
)(argc
, &args
);
Command
*c
= (Command
*) name
;
if ((cm
= (Command
*) genget(name
, (char **) cmdtab
, getnextcmd
)) != 0) {
return (Command
*) genget(name
, (char **) cmdtab2
, getnextcmd
);
signal(SIGQUIT
, SIG_DFL
);
#endif /* defined(unix) */
if (gets(line
) == NULL
) {
if (feof(stdin
) || ferror(stdin
))
printf("?Ambiguous command\n");
printf("?Invalid command\n");
if (c
->needconnect
&& !connected
) {
printf("?Need to be connected first.\n");
if ((*c
->handler
)(margc
, margv
)) {
#else /* defined(TN3270) */
#endif /* defined(TN3270) */
printf("Commands may be abbreviated. Commands are:\n\n");
for (c
= cmdtab
; c
->name
; c
++)
printf("%-*s\t%s\n", HELPINDENT
, c
->name
,
printf("?Ambiguous help command %s\n", arg
);
else if (c
== (Command
*)0)
printf("?Invalid help command %s\n", arg
);