133685Sbostic /* 233685Sbostic * Copyright (c) 1988 Regents of the University of California. 333685Sbostic * All rights reserved. 433685Sbostic * 533685Sbostic * Redistribution and use in source and binary forms are permitted 6*34898Sbostic * provided that the above copyright notice and this paragraph are 7*34898Sbostic * duplicated in all such forms and that any documentation, 8*34898Sbostic * advertising materials, and other materials related to such 9*34898Sbostic * distribution and use acknowledge that the software was developed 10*34898Sbostic * by the University of California, Berkeley. The name of the 11*34898Sbostic * University may not be used to endorse or promote products derived 12*34898Sbostic * from this software without specific prior written permission. 13*34898Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34898Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34898Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633685Sbostic */ 1733685Sbostic 1833685Sbostic #ifndef lint 19*34898Sbostic static char sccsid[] = "@(#)commands.c 1.7 (Berkeley) 06/29/88"; 2033685Sbostic #endif /* not lint */ 2133685Sbostic 2232144Sminshall #include <sys/types.h> 2332144Sminshall #include <sys/socket.h> 2432144Sminshall #include <netinet/in.h> 2532144Sminshall 2632144Sminshall #include <signal.h> 2732144Sminshall #include <netdb.h> 2832144Sminshall #include <ctype.h> 2932144Sminshall 3032144Sminshall #include <arpa/telnet.h> 3132144Sminshall 3234305Sminshall #include "general.h" 3334305Sminshall 3432381Sminshall #include "ring.h" 3532381Sminshall 3632144Sminshall #include "externs.h" 3732144Sminshall #include "defines.h" 3832144Sminshall #include "types.h" 3932144Sminshall 4032144Sminshall char *hostname; 4132144Sminshall 4232144Sminshall #define Ambiguous(s) ((char *)s == ambiguous) 4332144Sminshall static char *ambiguous; /* special return value for command routines */ 4432144Sminshall 4532144Sminshall typedef struct { 4632144Sminshall char *name; /* command name */ 4732144Sminshall char *help; /* help string */ 4832144Sminshall int (*handler)(); /* routine which executes command */ 4932144Sminshall int dohelp; /* Should we give general help information? */ 5032144Sminshall int needconnect; /* Do we need to be connected to execute? */ 5132144Sminshall } Command; 5232144Sminshall 5332144Sminshall static char line[200]; 5432144Sminshall static int margc; 5532144Sminshall static char *margv[20]; 5632144Sminshall 5732144Sminshall /* 5832144Sminshall * Various utility routines. 5932144Sminshall */ 6032144Sminshall 6132144Sminshall static void 6232144Sminshall makeargv() 6332144Sminshall { 6432144Sminshall register char *cp; 6532144Sminshall register char **argp = margv; 6632144Sminshall 6732144Sminshall margc = 0; 6832144Sminshall cp = line; 6932144Sminshall if (*cp == '!') { /* Special case shell escape */ 7032144Sminshall *argp++ = "!"; /* No room in string to get this */ 7132144Sminshall margc++; 7232144Sminshall cp++; 7332144Sminshall } 7432144Sminshall while (*cp) { 7532144Sminshall while (isspace(*cp)) 7632144Sminshall cp++; 7732144Sminshall if (*cp == '\0') 7832144Sminshall break; 7932144Sminshall *argp++ = cp; 8032144Sminshall margc += 1; 8132144Sminshall while (*cp != '\0' && !isspace(*cp)) 8232144Sminshall cp++; 8332144Sminshall if (*cp == '\0') 8432144Sminshall break; 8532144Sminshall *cp++ = '\0'; 8632144Sminshall } 8732144Sminshall *argp++ = 0; 8832144Sminshall } 8932144Sminshall 9032144Sminshall 9132144Sminshall static char ** 9232144Sminshall genget(name, table, next) 9332144Sminshall char *name; /* name to match */ 9432144Sminshall char **table; /* name entry in table */ 9532144Sminshall char **(*next)(); /* routine to return next entry in table */ 9632144Sminshall { 9732144Sminshall register char *p, *q; 9832144Sminshall register char **c, **found; 9932144Sminshall register int nmatches, longest; 10032144Sminshall 10132144Sminshall if (name == 0) { 10232144Sminshall return 0; 10332144Sminshall } 10432144Sminshall longest = 0; 10532144Sminshall nmatches = 0; 10632144Sminshall found = 0; 10732144Sminshall for (c = table; (p = *c) != 0; c = (*next)(c)) { 10832144Sminshall for (q = name; 10932144Sminshall (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++) 11032144Sminshall if (*q == 0) /* exact match? */ 11132144Sminshall return (c); 11232144Sminshall if (!*q) { /* the name was a prefix */ 11332144Sminshall if (q - name > longest) { 11432144Sminshall longest = q - name; 11532144Sminshall nmatches = 1; 11632144Sminshall found = c; 11732144Sminshall } else if (q - name == longest) 11832144Sminshall nmatches++; 11932144Sminshall } 12032144Sminshall } 12132144Sminshall if (nmatches > 1) 12232144Sminshall return (char **)ambiguous; 12332144Sminshall return (found); 12432144Sminshall } 12532144Sminshall 12632144Sminshall /* 12732144Sminshall * Make a character string into a number. 12832144Sminshall * 12932144Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 13032144Sminshall */ 13132144Sminshall 13232144Sminshall static 13332144Sminshall special(s) 13432144Sminshall register char *s; 13532144Sminshall { 13632144Sminshall register char c; 13732144Sminshall char b; 13832144Sminshall 13932144Sminshall switch (*s) { 14032144Sminshall case '^': 14132144Sminshall b = *++s; 14232144Sminshall if (b == '?') { 14332144Sminshall c = b | 0x40; /* DEL */ 14432144Sminshall } else { 14532144Sminshall c = b & 0x1f; 14632144Sminshall } 14732144Sminshall break; 14832144Sminshall default: 14932144Sminshall c = *s; 15032144Sminshall break; 15132144Sminshall } 15232144Sminshall return c; 15332144Sminshall } 15432144Sminshall 15532144Sminshall /* 15632144Sminshall * Construct a control character sequence 15732144Sminshall * for a special character. 15832144Sminshall */ 15932144Sminshall static char * 16032144Sminshall control(c) 16132144Sminshall register int c; 16232144Sminshall { 16332144Sminshall static char buf[3]; 16432144Sminshall 16532144Sminshall if (c == 0x7f) 16632144Sminshall return ("^?"); 16732144Sminshall if (c == '\377') { 16832144Sminshall return "off"; 16932144Sminshall } 17032144Sminshall if (c >= 0x20) { 17132144Sminshall buf[0] = c; 17232144Sminshall buf[1] = 0; 17332144Sminshall } else { 17432144Sminshall buf[0] = '^'; 17532144Sminshall buf[1] = '@'+c; 17632144Sminshall buf[2] = 0; 17732144Sminshall } 17832144Sminshall return (buf); 17932144Sminshall } 18032144Sminshall 18132144Sminshall 18232144Sminshall 18332144Sminshall /* 18432144Sminshall * The following are data structures and routines for 18532144Sminshall * the "send" command. 18632144Sminshall * 18732144Sminshall */ 18832144Sminshall 18932144Sminshall struct sendlist { 19032144Sminshall char *name; /* How user refers to it (case independent) */ 19132144Sminshall int what; /* Character to be sent (<0 ==> special) */ 19232144Sminshall char *help; /* Help information (0 ==> no help) */ 19332144Sminshall #if defined(NOT43) 19432144Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 19532144Sminshall #else /* defined(NOT43) */ 19632144Sminshall void (*routine)(); /* Routine to perform (for special ops) */ 19732144Sminshall #endif /* defined(NOT43) */ 19832144Sminshall }; 19932144Sminshall 20032144Sminshall #define SENDQUESTION -1 20132144Sminshall #define SENDESCAPE -3 20232144Sminshall 20332144Sminshall static struct sendlist Sendlist[] = { 20432144Sminshall { "ao", AO, "Send Telnet Abort output" }, 20532144Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 20632144Sminshall { "brk", BREAK, "Send Telnet Break" }, 20732144Sminshall { "ec", EC, "Send Telnet Erase Character" }, 20832144Sminshall { "el", EL, "Send Telnet Erase Line" }, 20932144Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 21032144Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 21132144Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 21232144Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 21332144Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 21432144Sminshall { "?", SENDQUESTION, "Display send options" }, 21532144Sminshall { 0 } 21632144Sminshall }; 21732144Sminshall 21832144Sminshall static struct sendlist Sendlist2[] = { /* some synonyms */ 21932144Sminshall { "break", BREAK, 0 }, 22032144Sminshall 22132144Sminshall { "intp", IP, 0 }, 22232144Sminshall { "interrupt", IP, 0 }, 22332144Sminshall { "intr", IP, 0 }, 22432144Sminshall 22532144Sminshall { "help", SENDQUESTION, 0 }, 22632144Sminshall 22732144Sminshall { 0 } 22832144Sminshall }; 22932144Sminshall 23032144Sminshall static char ** 23132144Sminshall getnextsend(name) 23232144Sminshall char *name; 23332144Sminshall { 23432144Sminshall struct sendlist *c = (struct sendlist *) name; 23532144Sminshall 23632144Sminshall return (char **) (c+1); 23732144Sminshall } 23832144Sminshall 23932144Sminshall static struct sendlist * 24032144Sminshall getsend(name) 24132144Sminshall char *name; 24232144Sminshall { 24332144Sminshall struct sendlist *sl; 24432144Sminshall 24532144Sminshall if ((sl = (struct sendlist *) 24632144Sminshall genget(name, (char **) Sendlist, getnextsend)) != 0) { 24732144Sminshall return sl; 24832144Sminshall } else { 24932144Sminshall return (struct sendlist *) 25032144Sminshall genget(name, (char **) Sendlist2, getnextsend); 25132144Sminshall } 25232144Sminshall } 25332144Sminshall 25432144Sminshall static 25532144Sminshall sendcmd(argc, argv) 25632144Sminshall int argc; 25732144Sminshall char **argv; 25832144Sminshall { 25932144Sminshall int what; /* what we are sending this time */ 26032144Sminshall int count; /* how many bytes we are going to need to send */ 26132144Sminshall int i; 26232144Sminshall int question = 0; /* was at least one argument a question */ 26332144Sminshall struct sendlist *s; /* pointer to current command */ 26432144Sminshall 26532144Sminshall if (argc < 2) { 26632144Sminshall printf("need at least one argument for 'send' command\n"); 26732144Sminshall printf("'send ?' for help\n"); 26832144Sminshall return 0; 26932144Sminshall } 27032144Sminshall /* 27132144Sminshall * First, validate all the send arguments. 27232144Sminshall * In addition, we see how much space we are going to need, and 27332144Sminshall * whether or not we will be doing a "SYNCH" operation (which 27432144Sminshall * flushes the network queue). 27532144Sminshall */ 27632144Sminshall count = 0; 27732144Sminshall for (i = 1; i < argc; i++) { 27832144Sminshall s = getsend(argv[i]); 27932144Sminshall if (s == 0) { 28032144Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 28132144Sminshall argv[i]); 28232144Sminshall return 0; 28332144Sminshall } else if (Ambiguous(s)) { 28432144Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 28532144Sminshall argv[i]); 28632144Sminshall return 0; 28732144Sminshall } 28832144Sminshall switch (s->what) { 28932144Sminshall case SENDQUESTION: 29032144Sminshall break; 29132144Sminshall case SENDESCAPE: 29232144Sminshall count += 1; 29332144Sminshall break; 29432144Sminshall case SYNCH: 29532144Sminshall count += 2; 29632144Sminshall break; 29732144Sminshall default: 29832144Sminshall count += 2; 29932144Sminshall break; 30032144Sminshall } 30132144Sminshall } 30232144Sminshall /* Now, do we have enough room? */ 30332144Sminshall if (NETROOM() < count) { 30432144Sminshall printf("There is not enough room in the buffer TO the network\n"); 30532144Sminshall printf("to process your request. Nothing will be done.\n"); 30632144Sminshall printf("('send synch' will throw away most data in the network\n"); 30732144Sminshall printf("buffer, if this might help.)\n"); 30832144Sminshall return 0; 30932144Sminshall } 31032144Sminshall /* OK, they are all OK, now go through again and actually send */ 31132144Sminshall for (i = 1; i < argc; i++) { 31232144Sminshall if ((s = getsend(argv[i])) == 0) { 31332144Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 31432144Sminshall quit(); 31532144Sminshall /*NOTREACHED*/ 31632144Sminshall } 31732144Sminshall if (s->routine) { 31832144Sminshall (*s->routine)(s); 31932144Sminshall } else { 32032144Sminshall switch (what = s->what) { 32132144Sminshall case SYNCH: 32232144Sminshall dosynch(); 32332144Sminshall break; 32432144Sminshall case SENDQUESTION: 32532144Sminshall for (s = Sendlist; s->name; s++) { 32632144Sminshall if (s->help) { 32732144Sminshall printf(s->name); 32832144Sminshall if (s->help) { 32932144Sminshall printf("\t%s", s->help); 33032144Sminshall } 33132144Sminshall printf("\n"); 33232144Sminshall } 33332144Sminshall } 33432144Sminshall question = 1; 33532144Sminshall break; 33632144Sminshall case SENDESCAPE: 33732144Sminshall NETADD(escape); 33832144Sminshall break; 33932144Sminshall default: 34032144Sminshall NET2ADD(IAC, what); 34132144Sminshall break; 34232144Sminshall } 34332144Sminshall } 34432144Sminshall } 34532144Sminshall return !question; 34632144Sminshall } 34732144Sminshall 34832144Sminshall /* 34932144Sminshall * The following are the routines and data structures referred 35032144Sminshall * to by the arguments to the "toggle" command. 35132144Sminshall */ 35232144Sminshall 35332144Sminshall static 35432144Sminshall lclchars() 35532144Sminshall { 35632144Sminshall donelclchars = 1; 35732144Sminshall return 1; 35832144Sminshall } 35932144Sminshall 36032144Sminshall static 36132144Sminshall togdebug() 36232144Sminshall { 36332144Sminshall #ifndef NOT43 36432144Sminshall if (net > 0 && 36532144Sminshall (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 36632144Sminshall perror("setsockopt (SO_DEBUG)"); 36732144Sminshall } 36832144Sminshall #else /* NOT43 */ 36932144Sminshall if (debug) { 37032144Sminshall if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 37132144Sminshall perror("setsockopt (SO_DEBUG)"); 37232144Sminshall } else 37332144Sminshall printf("Cannot turn off socket debugging\n"); 37432144Sminshall #endif /* NOT43 */ 37532144Sminshall return 1; 37632144Sminshall } 37732144Sminshall 37832144Sminshall 37932144Sminshall static int 38032144Sminshall togcrlf() 38132144Sminshall { 38232144Sminshall if (crlf) { 38332144Sminshall printf("Will send carriage returns as telnet <CR><LF>.\n"); 38432144Sminshall } else { 38532144Sminshall printf("Will send carriage returns as telnet <CR><NUL>.\n"); 38632144Sminshall } 38732144Sminshall return 1; 38832144Sminshall } 38932144Sminshall 39032144Sminshall 39132144Sminshall static int 39232144Sminshall togbinary() 39332144Sminshall { 39432144Sminshall donebinarytoggle = 1; 39532144Sminshall 39632144Sminshall if (myopts[TELOPT_BINARY] == 0) { /* Go into binary mode */ 39732144Sminshall NET2ADD(IAC, DO); 39832144Sminshall NETADD(TELOPT_BINARY); 39932144Sminshall printoption("<SENT", doopt, TELOPT_BINARY, 0); 40032144Sminshall NET2ADD(IAC, WILL); 40132144Sminshall NETADD(TELOPT_BINARY); 40232144Sminshall printoption("<SENT", doopt, TELOPT_BINARY, 0); 40332144Sminshall hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1; 40432144Sminshall printf("Negotiating binary mode with remote host.\n"); 40532144Sminshall } else { /* Turn off binary mode */ 40632144Sminshall NET2ADD(IAC, DONT); 40732144Sminshall NETADD(TELOPT_BINARY); 40832144Sminshall printoption("<SENT", dont, TELOPT_BINARY, 0); 40932144Sminshall NET2ADD(IAC, DONT); 41032144Sminshall NETADD(TELOPT_BINARY); 41132144Sminshall printoption("<SENT", dont, TELOPT_BINARY, 0); 41232144Sminshall hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0; 41332144Sminshall printf("Negotiating network ascii mode with remote host.\n"); 41432144Sminshall } 41532144Sminshall return 1; 41632144Sminshall } 41732144Sminshall 41832144Sminshall 41932144Sminshall 42032144Sminshall extern int togglehelp(); 42132144Sminshall 42232144Sminshall struct togglelist { 42332144Sminshall char *name; /* name of toggle */ 42432144Sminshall char *help; /* help message */ 42532144Sminshall int (*handler)(); /* routine to do actual setting */ 42632144Sminshall int dohelp; /* should we display help information */ 42732144Sminshall int *variable; 42832144Sminshall char *actionexplanation; 42932144Sminshall }; 43032144Sminshall 43132144Sminshall static struct togglelist Togglelist[] = { 43232144Sminshall { "autoflush", 43332144Sminshall "toggle flushing of output when sending interrupt characters", 43432144Sminshall 0, 43532144Sminshall 1, 43632144Sminshall &autoflush, 43732144Sminshall "flush output when sending interrupt characters" }, 43832144Sminshall { "autosynch", 43932144Sminshall "toggle automatic sending of interrupt characters in urgent mode", 44032144Sminshall 0, 44132144Sminshall 1, 44232144Sminshall &autosynch, 44332144Sminshall "send interrupt characters in urgent mode" }, 44432144Sminshall { "binary", 44532144Sminshall "toggle sending and receiving of binary data", 44632144Sminshall togbinary, 44732144Sminshall 1, 44832144Sminshall 0, 44932144Sminshall 0 }, 45032144Sminshall { "crlf", 45132144Sminshall "toggle sending carriage returns as telnet <CR><LF>", 45232144Sminshall togcrlf, 45332144Sminshall 1, 45432144Sminshall &crlf, 45532144Sminshall 0 }, 45632144Sminshall { "crmod", 45732144Sminshall "toggle mapping of received carriage returns", 45832144Sminshall 0, 45932144Sminshall 1, 46032144Sminshall &crmod, 46132144Sminshall "map carriage return on output" }, 46232144Sminshall { "localchars", 46332144Sminshall "toggle local recognition of certain control characters", 46432144Sminshall lclchars, 46532144Sminshall 1, 46632144Sminshall &localchars, 46732144Sminshall "recognize certain control characters" }, 46832144Sminshall { " ", "", 0, 1 }, /* empty line */ 46932144Sminshall { "debug", 47032144Sminshall "(debugging) toggle debugging", 47132144Sminshall togdebug, 47232144Sminshall 1, 47332144Sminshall &debug, 47432144Sminshall "turn on socket level debugging" }, 47532144Sminshall { "netdata", 47632144Sminshall "(debugging) toggle printing of hexadecimal network data", 47732144Sminshall 0, 47832144Sminshall 1, 47932144Sminshall &netdata, 48032144Sminshall "print hexadecimal representation of network traffic" }, 48132144Sminshall { "options", 48232144Sminshall "(debugging) toggle viewing of options processing", 48332144Sminshall 0, 48432144Sminshall 1, 48532144Sminshall &showoptions, 48632144Sminshall "show option processing" }, 48732144Sminshall { " ", "", 0, 1 }, /* empty line */ 48832144Sminshall { "?", 48932144Sminshall "display help information", 49032144Sminshall togglehelp, 49132144Sminshall 1 }, 49232144Sminshall { "help", 49332144Sminshall "display help information", 49432144Sminshall togglehelp, 49532144Sminshall 0 }, 49632144Sminshall { 0 } 49732144Sminshall }; 49832144Sminshall 49932144Sminshall static 50032144Sminshall togglehelp() 50132144Sminshall { 50232144Sminshall struct togglelist *c; 50332144Sminshall 50432144Sminshall for (c = Togglelist; c->name; c++) { 50532144Sminshall if (c->dohelp) { 50632144Sminshall printf("%s\t%s\n", c->name, c->help); 50732144Sminshall } 50832144Sminshall } 50932144Sminshall return 0; 51032144Sminshall } 51132144Sminshall 51232144Sminshall static char ** 51332144Sminshall getnexttoggle(name) 51432144Sminshall char *name; 51532144Sminshall { 51632144Sminshall struct togglelist *c = (struct togglelist *) name; 51732144Sminshall 51832144Sminshall return (char **) (c+1); 51932144Sminshall } 52032144Sminshall 52132144Sminshall static struct togglelist * 52232144Sminshall gettoggle(name) 52332144Sminshall char *name; 52432144Sminshall { 52532144Sminshall return (struct togglelist *) 52632144Sminshall genget(name, (char **) Togglelist, getnexttoggle); 52732144Sminshall } 52832144Sminshall 52932144Sminshall static 53032144Sminshall toggle(argc, argv) 53132144Sminshall int argc; 53232144Sminshall char *argv[]; 53332144Sminshall { 53432144Sminshall int retval = 1; 53532144Sminshall char *name; 53632144Sminshall struct togglelist *c; 53732144Sminshall 53832144Sminshall if (argc < 2) { 53932144Sminshall fprintf(stderr, 54032144Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 54132144Sminshall return 0; 54232144Sminshall } 54332144Sminshall argc--; 54432144Sminshall argv++; 54532144Sminshall while (argc--) { 54632144Sminshall name = *argv++; 54732144Sminshall c = gettoggle(name); 54832144Sminshall if (Ambiguous(c)) { 54932144Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 55032144Sminshall name); 55132144Sminshall return 0; 55232144Sminshall } else if (c == 0) { 55332144Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 55432144Sminshall name); 55532144Sminshall return 0; 55632144Sminshall } else { 55732144Sminshall if (c->variable) { 55832144Sminshall *c->variable = !*c->variable; /* invert it */ 55932144Sminshall if (c->actionexplanation) { 56032144Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 56132144Sminshall c->actionexplanation); 56232144Sminshall } 56332144Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 56432144Sminshall c->actionexplanation); 56532144Sminshall } 56632144Sminshall if (c->handler) { 56732144Sminshall retval &= (*c->handler)(c); 56832144Sminshall } 56932144Sminshall } 57032144Sminshall } 57132144Sminshall return retval; 57232144Sminshall } 57332144Sminshall 57432144Sminshall /* 57532144Sminshall * The following perform the "set" command. 57632144Sminshall */ 57732144Sminshall 57832144Sminshall struct setlist { 57932144Sminshall char *name; /* name */ 58032144Sminshall char *help; /* help information */ 58132144Sminshall char *charp; /* where it is located at */ 58232144Sminshall }; 58332144Sminshall 58432144Sminshall static struct setlist Setlist[] = { 58532144Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 58632144Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 58732144Sminshall { " ", "" }, 58832144Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 58932144Sminshall { "erase", "character to cause an Erase Character", &termEraseChar }, 59032144Sminshall { "flushoutput", "character to cause an Abort Oubput", &termFlushChar }, 59132144Sminshall { "interrupt", "character to cause an Interrupt Process", &termIntChar }, 59232144Sminshall { "kill", "character to cause an Erase Line", &termKillChar }, 59332144Sminshall { "quit", "character to cause a Break", &termQuitChar }, 59432144Sminshall { "eof", "character to cause an EOF ", &termEofChar }, 59532144Sminshall { 0 } 59632144Sminshall }; 59732144Sminshall 59832144Sminshall static char ** 59932144Sminshall getnextset(name) 60032144Sminshall char *name; 60132144Sminshall { 60232144Sminshall struct setlist *c = (struct setlist *)name; 60332144Sminshall 60432144Sminshall return (char **) (c+1); 60532144Sminshall } 60632144Sminshall 60732144Sminshall static struct setlist * 60832144Sminshall getset(name) 60932144Sminshall char *name; 61032144Sminshall { 61132144Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 61232144Sminshall } 61332144Sminshall 61432144Sminshall static 61532144Sminshall setcmd(argc, argv) 61632144Sminshall int argc; 61732144Sminshall char *argv[]; 61832144Sminshall { 61932144Sminshall int value; 62032144Sminshall struct setlist *ct; 62132144Sminshall 62232144Sminshall /* XXX back we go... sigh */ 62332144Sminshall if (argc != 3) { 62432144Sminshall if ((argc == 2) && 62532144Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 62632144Sminshall for (ct = Setlist; ct->name; ct++) { 62732144Sminshall printf("%s\t%s\n", ct->name, ct->help); 62832144Sminshall } 62932144Sminshall printf("?\tdisplay help information\n"); 63032144Sminshall } else { 63132144Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 63232144Sminshall } 63332144Sminshall return 0; 63432144Sminshall } 63532144Sminshall 63632144Sminshall ct = getset(argv[1]); 63732144Sminshall if (ct == 0) { 63832144Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 63932144Sminshall argv[1]); 64032144Sminshall return 0; 64132144Sminshall } else if (Ambiguous(ct)) { 64232144Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 64332144Sminshall argv[1]); 64432144Sminshall return 0; 64532144Sminshall } else { 64632144Sminshall if (strcmp("off", argv[2])) { 64732144Sminshall value = special(argv[2]); 64832144Sminshall } else { 64932144Sminshall value = -1; 65032144Sminshall } 65132144Sminshall *(ct->charp) = value; 65232144Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 65332144Sminshall } 65432144Sminshall return 1; 65532144Sminshall } 65632144Sminshall 65732144Sminshall /* 65832144Sminshall * The following are the data structures and routines for the 65932144Sminshall * 'mode' command. 66032144Sminshall */ 66132144Sminshall 66232144Sminshall static 66332144Sminshall dolinemode() 66432144Sminshall { 66532144Sminshall if (hisopts[TELOPT_SGA]) { 66632144Sminshall wontoption(TELOPT_SGA, 0); 66732144Sminshall } 66832144Sminshall if (hisopts[TELOPT_ECHO]) { 66932144Sminshall wontoption(TELOPT_ECHO, 0); 67032144Sminshall } 67132144Sminshall return 1; 67232144Sminshall } 67332144Sminshall 67432144Sminshall static 67532144Sminshall docharmode() 67632144Sminshall { 67732144Sminshall if (!hisopts[TELOPT_SGA]) { 67832144Sminshall willoption(TELOPT_SGA, 0); 67932144Sminshall } 68032144Sminshall if (!hisopts[TELOPT_ECHO]) { 68132144Sminshall willoption(TELOPT_ECHO, 0); 68232144Sminshall } 68332144Sminshall return 1; 68432144Sminshall } 68532144Sminshall 68632144Sminshall static Command Mode_commands[] = { 68732144Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 68832144Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 68932144Sminshall { 0 }, 69032144Sminshall }; 69132144Sminshall 69232144Sminshall static char ** 69332144Sminshall getnextmode(name) 69432144Sminshall char *name; 69532144Sminshall { 69632144Sminshall Command *c = (Command *) name; 69732144Sminshall 69832144Sminshall return (char **) (c+1); 69932144Sminshall } 70032144Sminshall 70132144Sminshall static Command * 70232144Sminshall getmodecmd(name) 70332144Sminshall char *name; 70432144Sminshall { 70532144Sminshall return (Command *) genget(name, (char **) Mode_commands, getnextmode); 70632144Sminshall } 70732144Sminshall 70832144Sminshall static 70932144Sminshall modecmd(argc, argv) 71032144Sminshall int argc; 71132144Sminshall char *argv[]; 71232144Sminshall { 71332144Sminshall Command *mt; 71432144Sminshall 71532144Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 71632144Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 71732144Sminshall for (mt = Mode_commands; mt->name; mt++) { 71832144Sminshall printf("%s\t%s\n", mt->name, mt->help); 71932144Sminshall } 72032144Sminshall return 0; 72132144Sminshall } 72232144Sminshall mt = getmodecmd(argv[1]); 72332144Sminshall if (mt == 0) { 72432144Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 72532144Sminshall return 0; 72632144Sminshall } else if (Ambiguous(mt)) { 72732144Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 72832144Sminshall return 0; 72932144Sminshall } else { 73032144Sminshall (*mt->handler)(); 73132144Sminshall } 73232144Sminshall return 1; 73332144Sminshall } 73432144Sminshall 73532144Sminshall /* 73632144Sminshall * The following data structures and routines implement the 73732144Sminshall * "display" command. 73832144Sminshall */ 73932144Sminshall 74032144Sminshall static 74132144Sminshall display(argc, argv) 74232144Sminshall int argc; 74332144Sminshall char *argv[]; 74432144Sminshall { 74532144Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 74632144Sminshall if (*tl->variable) { \ 74732144Sminshall printf("will"); \ 74832144Sminshall } else { \ 74932144Sminshall printf("won't"); \ 75032144Sminshall } \ 75132144Sminshall printf(" %s.\n", tl->actionexplanation); \ 75232144Sminshall } 75332144Sminshall 75432144Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 75532144Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 75632144Sminshall } 75732144Sminshall 75832144Sminshall struct togglelist *tl; 75932144Sminshall struct setlist *sl; 76032144Sminshall 76132144Sminshall if (argc == 1) { 76232144Sminshall for (tl = Togglelist; tl->name; tl++) { 76332144Sminshall dotog(tl); 76432144Sminshall } 76532144Sminshall printf("\n"); 76632144Sminshall for (sl = Setlist; sl->name; sl++) { 76732144Sminshall doset(sl); 76832144Sminshall } 76932144Sminshall } else { 77032144Sminshall int i; 77132144Sminshall 77232144Sminshall for (i = 1; i < argc; i++) { 77332144Sminshall sl = getset(argv[i]); 77432144Sminshall tl = gettoggle(argv[i]); 77532144Sminshall if (Ambiguous(sl) || Ambiguous(tl)) { 77632144Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 77732144Sminshall return 0; 77832144Sminshall } else if (!sl && !tl) { 77932144Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 78032144Sminshall return 0; 78132144Sminshall } else { 78232144Sminshall if (tl) { 78332144Sminshall dotog(tl); 78432144Sminshall } 78532144Sminshall if (sl) { 78632144Sminshall doset(sl); 78732144Sminshall } 78832144Sminshall } 78932144Sminshall } 79032144Sminshall } 79132144Sminshall return 1; 79232144Sminshall #undef doset 79332144Sminshall #undef dotog 79432144Sminshall } 79532144Sminshall 79632144Sminshall /* 79732144Sminshall * The following are the data structures, and many of the routines, 79832144Sminshall * relating to command processing. 79932144Sminshall */ 80032144Sminshall 80132144Sminshall /* 80232144Sminshall * Set the escape character. 80332144Sminshall */ 80432144Sminshall static 80532144Sminshall setescape(argc, argv) 80632144Sminshall int argc; 80732144Sminshall char *argv[]; 80832144Sminshall { 80932144Sminshall register char *arg; 81032144Sminshall char buf[50]; 81132144Sminshall 81232144Sminshall printf( 81332144Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 81432144Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 81532144Sminshall if (argc > 2) 81632144Sminshall arg = argv[1]; 81732144Sminshall else { 81832144Sminshall printf("new escape character: "); 81934849Sminshall (void) gets(buf); 82032144Sminshall arg = buf; 82132144Sminshall } 82232144Sminshall if (arg[0] != '\0') 82332144Sminshall escape = arg[0]; 82432144Sminshall if (!In3270) { 82532144Sminshall printf("Escape character is '%s'.\n", control(escape)); 82632144Sminshall } 82734849Sminshall (void) fflush(stdout); 82832144Sminshall return 1; 82932144Sminshall } 83032144Sminshall 83132144Sminshall /*VARARGS*/ 83232144Sminshall static 83332144Sminshall togcrmod() 83432144Sminshall { 83532144Sminshall crmod = !crmod; 83632144Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 83732144Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 83834849Sminshall (void) fflush(stdout); 83932144Sminshall return 1; 84032144Sminshall } 84132144Sminshall 84232144Sminshall /*VARARGS*/ 84332144Sminshall suspend() 84432144Sminshall { 84532144Sminshall setcommandmode(); 84632144Sminshall #if defined(unix) 84734849Sminshall (void) kill(0, SIGTSTP); 84832144Sminshall #endif /* defined(unix) */ 84932144Sminshall /* reget parameters in case they were changed */ 85032144Sminshall TerminalSaveState(); 85132144Sminshall setconnmode(); 85232144Sminshall return 1; 85332144Sminshall } 85432144Sminshall 85532144Sminshall /*VARARGS*/ 85632144Sminshall static 85732144Sminshall bye(argc, argv) 85832144Sminshall int argc; /* Number of arguments */ 85932144Sminshall char *argv[]; /* arguments */ 86032144Sminshall { 86132144Sminshall if (connected) { 86234849Sminshall (void) shutdown(net, 2); 86332144Sminshall printf("Connection closed.\n"); 86434849Sminshall (void) NetClose(net); 86532144Sminshall connected = 0; 86632144Sminshall /* reset options */ 86732144Sminshall tninit(); 86832144Sminshall #if defined(TN3270) 86932144Sminshall SetIn3270(); /* Get out of 3270 mode */ 87032144Sminshall #endif /* defined(TN3270) */ 87132144Sminshall } 87232144Sminshall if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 87332144Sminshall longjmp(toplevel, 1); 87432144Sminshall /* NOTREACHED */ 87532144Sminshall } 87632144Sminshall return 1; /* Keep lint, etc., happy */ 87732144Sminshall } 87832144Sminshall 87932144Sminshall /*VARARGS*/ 88032144Sminshall quit() 88132144Sminshall { 88232144Sminshall (void) call(bye, "bye", "fromquit", 0); 88332144Sminshall Exit(0); 88432144Sminshall return 1; /* just to keep lint happy */ 88532144Sminshall } 88632144Sminshall 88732144Sminshall /* 88832144Sminshall * Print status about the connection. 88932144Sminshall */ 89034849Sminshall /*ARGSUSED*/ 89132144Sminshall static 89232144Sminshall status(argc, argv) 89332144Sminshall int argc; 89432144Sminshall char *argv[]; 89532144Sminshall { 89632144Sminshall if (connected) { 89732144Sminshall printf("Connected to %s.\n", hostname); 89832144Sminshall if (argc < 2) { 89932144Sminshall printf("Operating in %s.\n", 90032144Sminshall modelist[getconnmode()].modedescriptions); 90132144Sminshall if (localchars) { 90232144Sminshall printf("Catching signals locally.\n"); 90332144Sminshall } 90432144Sminshall } 90532144Sminshall } else { 90632144Sminshall printf("No connection.\n"); 90732144Sminshall } 90832144Sminshall # if !defined(TN3270) 90932144Sminshall printf("Escape character is '%s'.\n", control(escape)); 91034849Sminshall (void) fflush(stdout); 91132144Sminshall # else /* !defined(TN3270) */ 91232144Sminshall if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 91332144Sminshall printf("Escape character is '%s'.\n", control(escape)); 91432144Sminshall } 91532144Sminshall # if defined(unix) 91632144Sminshall if (In3270 && transcom) { 91732144Sminshall printf("Transparent mode command is '%s'.\n", transcom); 91832144Sminshall } 91932144Sminshall # endif /* defined(unix) */ 92034849Sminshall (void) fflush(stdout); 92132144Sminshall if (In3270) { 92232144Sminshall return 0; 92332144Sminshall } 92432144Sminshall # endif /* defined(TN3270) */ 92532144Sminshall return 1; 92632144Sminshall } 92732144Sminshall 92832144Sminshall 92932144Sminshall 93032144Sminshall int 93132144Sminshall tn(argc, argv) 93232144Sminshall int argc; 93332144Sminshall char *argv[]; 93432144Sminshall { 93532144Sminshall register struct hostent *host = 0; 93632144Sminshall struct sockaddr_in sin; 93732144Sminshall struct servent *sp = 0; 93832144Sminshall static char hnamebuf[32]; 93934849Sminshall unsigned long inet_addr(); 94032144Sminshall 94132144Sminshall 94232144Sminshall #if defined(MSDOS) 94332144Sminshall char *cp; 94432144Sminshall #endif /* defined(MSDOS) */ 94532144Sminshall 94632144Sminshall if (connected) { 94732144Sminshall printf("?Already connected to %s\n", hostname); 94832144Sminshall return 0; 94932144Sminshall } 95032144Sminshall if (argc < 2) { 95132144Sminshall (void) strcpy(line, "Connect "); 95232144Sminshall printf("(to) "); 95334849Sminshall (void) gets(&line[strlen(line)]); 95432144Sminshall makeargv(); 95532144Sminshall argc = margc; 95632144Sminshall argv = margv; 95732144Sminshall } 95832144Sminshall if ((argc < 2) || (argc > 3)) { 95932144Sminshall printf("usage: %s host-name [port]\n", argv[0]); 96032144Sminshall return 0; 96132144Sminshall } 96232144Sminshall #if defined(MSDOS) 96332144Sminshall for (cp = argv[1]; *cp; cp++) { 96432144Sminshall if (isupper(*cp)) { 96532144Sminshall *cp = tolower(*cp); 96632144Sminshall } 96732144Sminshall } 96832144Sminshall #endif /* defined(MSDOS) */ 96932144Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 97032144Sminshall if (sin.sin_addr.s_addr != -1) { 97132144Sminshall sin.sin_family = AF_INET; 97232144Sminshall (void) strcpy(hnamebuf, argv[1]); 97332144Sminshall hostname = hnamebuf; 97432144Sminshall } else { 97532144Sminshall host = gethostbyname(argv[1]); 97632144Sminshall if (host) { 97732144Sminshall sin.sin_family = host->h_addrtype; 97832144Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 97932144Sminshall memcpy((caddr_t)&sin.sin_addr, 98032144Sminshall host->h_addr_list[0], host->h_length); 98132144Sminshall #else /* defined(h_addr) */ 98232144Sminshall memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); 98332144Sminshall #endif /* defined(h_addr) */ 98432144Sminshall hostname = host->h_name; 98532144Sminshall } else { 98632144Sminshall printf("%s: unknown host\n", argv[1]); 98732144Sminshall return 0; 98832144Sminshall } 98932144Sminshall } 99032144Sminshall if (argc == 3) { 99132144Sminshall sin.sin_port = atoi(argv[2]); 99232144Sminshall if (sin.sin_port == 0) { 99332144Sminshall sp = getservbyname(argv[2], "tcp"); 99432144Sminshall if (sp) 99532144Sminshall sin.sin_port = sp->s_port; 99632144Sminshall else { 99732144Sminshall printf("%s: bad port number\n", argv[2]); 99832144Sminshall return 0; 99932144Sminshall } 100032144Sminshall } else { 100134849Sminshall #if !defined(htons) 100234849Sminshall u_short htons(); 100334849Sminshall #endif /* !defined(htons) */ 100434849Sminshall 100532144Sminshall sin.sin_port = atoi(argv[2]); 100632144Sminshall sin.sin_port = htons(sin.sin_port); 100732144Sminshall } 100832144Sminshall telnetport = 0; 100932144Sminshall } else { 101032144Sminshall if (sp == 0) { 101132144Sminshall sp = getservbyname("telnet", "tcp"); 101232144Sminshall if (sp == 0) { 101334849Sminshall fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 101432144Sminshall return 0; 101532144Sminshall } 101632144Sminshall sin.sin_port = sp->s_port; 101732144Sminshall } 101832144Sminshall telnetport = 1; 101932144Sminshall } 102032144Sminshall printf("Trying...\n"); 102132144Sminshall do { 102232144Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 102332144Sminshall if (net < 0) { 102432144Sminshall perror("telnet: socket"); 102532144Sminshall return 0; 102632144Sminshall } 102732144Sminshall if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 102832144Sminshall perror("setsockopt (SO_DEBUG)"); 102932144Sminshall } 103032144Sminshall 103132144Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 103232144Sminshall #if defined(h_addr) /* In 4.3, this is a #define */ 103332144Sminshall if (host && host->h_addr_list[1]) { 103432144Sminshall int oerrno = errno; 103534849Sminshall extern char *inet_ntoa(); 103632144Sminshall 103732144Sminshall fprintf(stderr, "telnet: connect to address %s: ", 103832144Sminshall inet_ntoa(sin.sin_addr)); 103932144Sminshall errno = oerrno; 104032144Sminshall perror((char *)0); 104132144Sminshall host->h_addr_list++; 104232144Sminshall memcpy((caddr_t)&sin.sin_addr, 104332144Sminshall host->h_addr_list[0], host->h_length); 104432144Sminshall fprintf(stderr, "Trying %s...\n", 104532144Sminshall inet_ntoa(sin.sin_addr)); 104632144Sminshall (void) NetClose(net); 104732144Sminshall continue; 104832144Sminshall } 104932144Sminshall #endif /* defined(h_addr) */ 105032144Sminshall perror("telnet: Unable to connect to remote host"); 105132144Sminshall return 0; 105232144Sminshall } 105332144Sminshall connected++; 105432144Sminshall } while (connected == 0); 105534849Sminshall (void) call(status, "status", "notmuch", 0); 105632144Sminshall if (setjmp(peerdied) == 0) 105732144Sminshall telnet(); 105834849Sminshall (void) NetClose(net); 105932381Sminshall ExitString("Connection closed by foreign host.\n",1); 106032144Sminshall /*NOTREACHED*/ 106132144Sminshall } 106232144Sminshall 106332144Sminshall 106432144Sminshall #define HELPINDENT (sizeof ("connect")) 106532144Sminshall 106632144Sminshall static char 106732144Sminshall openhelp[] = "connect to a site", 106832144Sminshall closehelp[] = "close current connection", 106932144Sminshall quithelp[] = "exit telnet", 107032144Sminshall statushelp[] = "print status information", 107132144Sminshall helphelp[] = "print help information", 107232144Sminshall sendhelp[] = "transmit special characters ('send ?' for more)", 107332144Sminshall sethelp[] = "set operating parameters ('set ?' for more)", 107432144Sminshall togglestring[] ="toggle operating parameters ('toggle ?' for more)", 107532144Sminshall displayhelp[] = "display operating parameters", 107632144Sminshall #if defined(TN3270) && defined(unix) 107732144Sminshall transcomhelp[] = "specify Unix command for transparent mode pipe", 107832144Sminshall #endif /* defined(TN3270) && defined(unix) */ 107932144Sminshall #if defined(unix) 108032144Sminshall zhelp[] = "suspend telnet", 108132144Sminshall #endif /* defined(unix */ 108232144Sminshall #if defined(TN3270) 108332144Sminshall shellhelp[] = "invoke a subshell", 108432144Sminshall #endif /* defined(TN3270) */ 108532144Sminshall modehelp[] = "try to enter line-by-line or character-at-a-time mode"; 108632144Sminshall 108732144Sminshall extern int help(), shell(); 108832144Sminshall 108932144Sminshall static Command cmdtab[] = { 109032144Sminshall { "close", closehelp, bye, 1, 1 }, 109132144Sminshall { "display", displayhelp, display, 1, 0 }, 109232144Sminshall { "mode", modehelp, modecmd, 1, 1 }, 109332144Sminshall { "open", openhelp, tn, 1, 0 }, 109432144Sminshall { "quit", quithelp, quit, 1, 0 }, 109532144Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 109632144Sminshall { "set", sethelp, setcmd, 1, 0 }, 109732144Sminshall { "status", statushelp, status, 1, 0 }, 109832144Sminshall { "toggle", togglestring, toggle, 1, 0 }, 109932144Sminshall #if defined(TN3270) && defined(unix) 110032144Sminshall { "transcom", transcomhelp, settranscom, 1, 0 }, 110132144Sminshall #endif /* defined(TN3270) && defined(unix) */ 110232144Sminshall #if defined(unix) 110332144Sminshall { "z", zhelp, suspend, 1, 0 }, 110432144Sminshall #endif /* defined(unix) */ 110532144Sminshall #if defined(TN3270) 110632144Sminshall { "!", shellhelp, shell, 1, 1 }, 110732144Sminshall #endif /* defined(TN3270) */ 110832144Sminshall { "?", helphelp, help, 1, 0 }, 110932144Sminshall 0 111032144Sminshall }; 111132144Sminshall 111232144Sminshall static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 111332144Sminshall static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 111432144Sminshall 111532144Sminshall static Command cmdtab2[] = { 111632144Sminshall { "help", helphelp, help, 0, 0 }, 111732144Sminshall { "escape", escapehelp, setescape, 1, 0 }, 111832144Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 111932144Sminshall 0 112032144Sminshall }; 112132144Sminshall 112232144Sminshall /* 112332144Sminshall * Call routine with argc, argv set from args (terminated by 0). 112432144Sminshall * VARARGS2 112532144Sminshall */ 112632144Sminshall static 112732144Sminshall call(routine, args) 112832144Sminshall int (*routine)(); 112932144Sminshall char *args; 113032144Sminshall { 113132144Sminshall register char **argp; 113232144Sminshall register int argc; 113332144Sminshall 113432144Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 113532144Sminshall ; 113632144Sminshall return (*routine)(argc, &args); 113732144Sminshall } 113832144Sminshall 113932144Sminshall static char ** 114032144Sminshall getnextcmd(name) 114132144Sminshall char *name; 114232144Sminshall { 114332144Sminshall Command *c = (Command *) name; 114432144Sminshall 114532144Sminshall return (char **) (c+1); 114632144Sminshall } 114732144Sminshall 114832144Sminshall static Command * 114932144Sminshall getcmd(name) 115032144Sminshall char *name; 115132144Sminshall { 115232144Sminshall Command *cm; 115332144Sminshall 115432144Sminshall if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) { 115532144Sminshall return cm; 115632144Sminshall } else { 115732144Sminshall return (Command *) genget(name, (char **) cmdtab2, getnextcmd); 115832144Sminshall } 115932144Sminshall } 116032144Sminshall 116132144Sminshall void 116232144Sminshall command(top) 116332144Sminshall int top; 116432144Sminshall { 116532144Sminshall register Command *c; 116632144Sminshall 116732144Sminshall setcommandmode(); 116832144Sminshall if (!top) { 116932144Sminshall putchar('\n'); 117032144Sminshall } else { 117132144Sminshall #if defined(unix) 117232144Sminshall signal(SIGINT, SIG_DFL); 117332144Sminshall signal(SIGQUIT, SIG_DFL); 117432144Sminshall #endif /* defined(unix) */ 117532144Sminshall } 117632144Sminshall for (;;) { 117732144Sminshall printf("%s> ", prompt); 117832144Sminshall if (gets(line) == NULL) { 117932144Sminshall if (feof(stdin) || ferror(stdin)) 118032144Sminshall quit(); 118132144Sminshall break; 118232144Sminshall } 118332144Sminshall if (line[0] == 0) 118432144Sminshall break; 118532144Sminshall makeargv(); 118632144Sminshall c = getcmd(margv[0]); 118732144Sminshall if (Ambiguous(c)) { 118832144Sminshall printf("?Ambiguous command\n"); 118932144Sminshall continue; 119032144Sminshall } 119132144Sminshall if (c == 0) { 119232144Sminshall printf("?Invalid command\n"); 119332144Sminshall continue; 119432144Sminshall } 119532144Sminshall if (c->needconnect && !connected) { 119632144Sminshall printf("?Need to be connected first.\n"); 119732144Sminshall continue; 119832144Sminshall } 119932144Sminshall if ((*c->handler)(margc, margv)) { 120032144Sminshall break; 120132144Sminshall } 120232144Sminshall } 120332144Sminshall if (!top) { 120432144Sminshall if (!connected) { 120532144Sminshall longjmp(toplevel, 1); 120632144Sminshall /*NOTREACHED*/ 120732144Sminshall } 120832144Sminshall #if defined(TN3270) 120932144Sminshall if (shell_active == 0) { 121032144Sminshall setconnmode(); 121132144Sminshall } 121232144Sminshall #else /* defined(TN3270) */ 121332144Sminshall setconnmode(); 121432144Sminshall #endif /* defined(TN3270) */ 121532144Sminshall } 121632144Sminshall } 121732144Sminshall 121832144Sminshall /* 121932144Sminshall * Help command. 122032144Sminshall */ 122132144Sminshall static 122232144Sminshall help(argc, argv) 122332144Sminshall int argc; 122432144Sminshall char *argv[]; 122532144Sminshall { 122632144Sminshall register Command *c; 122732144Sminshall 122832144Sminshall if (argc == 1) { 122932144Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 123032144Sminshall for (c = cmdtab; c->name; c++) 123132144Sminshall if (c->dohelp) { 123232144Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 123332144Sminshall c->help); 123432144Sminshall } 123532144Sminshall return 0; 123632144Sminshall } 123732144Sminshall while (--argc > 0) { 123832144Sminshall register char *arg; 123932144Sminshall arg = *++argv; 124032144Sminshall c = getcmd(arg); 124132144Sminshall if (Ambiguous(c)) 124232144Sminshall printf("?Ambiguous help command %s\n", arg); 124332144Sminshall else if (c == (Command *)0) 124432144Sminshall printf("?Invalid help command %s\n", arg); 124532144Sminshall else 124632144Sminshall printf("%s\n", c->help); 124732144Sminshall } 124832144Sminshall return 0; 124932144Sminshall } 1250