121580Sdist /* 221580Sdist * Copyright (c) 1983 Regents of the University of California. 321580Sdist * All rights reserved. The Berkeley software License Agreement 421580Sdist * specifies the terms and conditions for redistribution. 521580Sdist */ 621580Sdist 711758Ssam #ifndef lint 821580Sdist char copyright[] = 921580Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1021580Sdist All rights reserved.\n"; 1121580Sdist #endif not lint 1211758Ssam 1321580Sdist #ifndef lint 14*28066Sminshall static char sccsid[] = "@(#)telnet.c 5.15 (Berkeley) 05/13/86"; 1521580Sdist #endif not lint 1621580Sdist 176000Sroot /* 186000Sroot * User telnet program. 19*28066Sminshall * 20*28066Sminshall * Many of the FUNCTIONAL changes in this newest version of telnet 21*28066Sminshall * were suggested by Dave Borman of Cray Research, Inc. 226000Sroot */ 23*28066Sminshall 249217Ssam #include <sys/types.h> 259217Ssam #include <sys/socket.h> 269972Ssam #include <sys/ioctl.h> 2727178Sminshall #include <sys/time.h> 289217Ssam 299217Ssam #include <netinet/in.h> 309217Ssam 3112212Ssam #define TELOPTS 3212212Ssam #include <arpa/telnet.h> 3327186Sminshall #include <arpa/inet.h> 3412212Ssam 356000Sroot #include <stdio.h> 366000Sroot #include <ctype.h> 376000Sroot #include <errno.h> 386000Sroot #include <signal.h> 396000Sroot #include <setjmp.h> 408345Ssam #include <netdb.h> 4127186Sminshall #include <strings.h> 429217Ssam 4327178Sminshall 4427178Sminshall 4527676Sminshall #ifndef FD_SETSIZE 4627178Sminshall /* 4727178Sminshall * The following is defined just in case someone should want to run 4827178Sminshall * this telnet on a 4.2 system. 4927178Sminshall * 5027178Sminshall */ 5127178Sminshall 5227676Sminshall #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) 5327676Sminshall #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) 5427676Sminshall #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) 5527676Sminshall #define FD_ZERO(p) ((p)->fds_bits[0] = 0) 5627178Sminshall 5727178Sminshall #endif 5827178Sminshall 5927228Sminshall #define strip(x) ((x)&0x7f) 606000Sroot 6127228Sminshall char ttyobuf[2*BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; 6227228Sminshall #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } } 6327228Sminshall #define TTYLOC() (tfrontp) 6427228Sminshall #define TTYMAX() (ttyobuf+sizeof ttyobuf-1) 6527228Sminshall #define TTYMIN() (netobuf) 6627228Sminshall #define TTYBYTES() (tfrontp-tbackp) 6727228Sminshall #define TTYROOM() (TTYMAX()-TTYLOC()+1) 6827088Sminshall 6927228Sminshall char netobuf[2*BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 7027088Sminshall #define NETADD(c) { *nfrontp++ = c; } 7127088Sminshall #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } 7227088Sminshall #define NETLOC() (nfrontp) 7327228Sminshall #define NETMAX() (netobuf+sizeof netobuf-1) 7427228Sminshall #define NETBYTES() (nfrontp-nbackp) 7527228Sminshall #define NETROOM() (NETMAX()-NETLOC()+1) 7627088Sminshall char *neturg = 0; /* one past last byte of urgent data */ 776000Sroot 7827676Sminshall char subbuffer[100], *subpointer, *subend; /* buffer for sub-options */ 7927676Sminshall #define SB_CLEAR() subpointer = subbuffer; 8027676Sminshall #define SB_TERM() subend = subpointer; 8127676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 8227676Sminshall *subpointer++ = (c); \ 8327676Sminshall } 8427676Sminshall 856000Sroot char hisopts[256]; 866000Sroot char myopts[256]; 876000Sroot 886000Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 896000Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 906000Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 916000Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 926000Sroot 9327088Sminshall struct cmd { 9427088Sminshall char *name; /* command name */ 9527088Sminshall char *help; /* help string */ 9627088Sminshall int (*handler)(); /* routine which executes command */ 9727088Sminshall int dohelp; /* Should we give general help information? */ 9827088Sminshall int needconnect; /* Do we need to be connected to execute? */ 9927088Sminshall }; 10027088Sminshall 1016000Sroot int connected; 1026000Sroot int net; 10327088Sminshall int tout; 1049972Ssam int showoptions = 0; 10510339Ssam int debug = 0; 1069972Ssam int crmod = 0; 10727088Sminshall int netdata = 0; 10827021Sminshall static FILE *NetTrace; 10925289Skarels int telnetport = 1; 11027088Sminshall 11127088Sminshall 1126000Sroot char *prompt; 1139972Ssam char escape = CTRL(]); 11427110Sminshall char echoc = CTRL(E); 1156000Sroot 11627186Sminshall int SYNCHing = 0; /* we are in TELNET SYNCH mode */ 11727186Sminshall int flushout = 0; /* flush output */ 11827228Sminshall int autoflush = 0; /* flush output when interrupting? */ 11927186Sminshall int autosynch = 0; /* send interrupt characters with SYNCH? */ 12027261Sminshall int localchars = 0; /* we recognize interrupt/quit */ 12127261Sminshall int donelclchars = 0; /* the user has set "localchars" */ 12227186Sminshall int dontlecho = 0; /* do we suppress local echoing right now? */ 12327186Sminshall 1246000Sroot char line[200]; 1256000Sroot int margc; 1266000Sroot char *margv[20]; 1276000Sroot 1286000Sroot jmp_buf toplevel; 1296000Sroot jmp_buf peerdied; 1306000Sroot 1316000Sroot extern int errno; 1326000Sroot 1336000Sroot 1349972Ssam struct sockaddr_in sin; 1356000Sroot 1366000Sroot struct cmd *getcmd(); 1378345Ssam struct servent *sp; 1386000Sroot 13927110Sminshall struct tchars otc, ntc; 14027228Sminshall struct ltchars oltc, nltc; 14127110Sminshall struct sgttyb ottyb, nttyb; 14227110Sminshall int globalmode = 0; 14327110Sminshall int flushline = 1; 1448378Ssam 14527110Sminshall char *hostname; 14627110Sminshall char hnamebuf[32]; 14727110Sminshall 14827110Sminshall /* 14927110Sminshall * The following are some clocks used to decide how to interpret 15027178Sminshall * the relationship between various variables. 15127110Sminshall */ 15227110Sminshall 15327110Sminshall struct { 15427110Sminshall int 15527110Sminshall system, /* what the current time is */ 15627110Sminshall echotoggle, /* last time user entered echo character */ 15727178Sminshall modenegotiated, /* last time operating mode negotiated */ 15827178Sminshall didnetreceive, /* last time we read data from network */ 15927178Sminshall gotDM; /* when did we last see a data mark */ 16027186Sminshall } clocks; 16127110Sminshall 16227186Sminshall #define settimer(x) clocks.x = clocks.system++ 16327110Sminshall 16427110Sminshall /* 16527110Sminshall * Various utility routines. 16627110Sminshall */ 1676000Sroot 16827186Sminshall char *ambiguous; /* special return value */ 16927186Sminshall #define Ambiguous(t) ((t)&ambiguous) 17027186Sminshall 17127186Sminshall 17227088Sminshall char ** 17327088Sminshall genget(name, table, next) 17427088Sminshall char *name; /* name to match */ 17527088Sminshall char **table; /* name entry in table */ 17627088Sminshall char **(*next)(); /* routine to return next entry in table */ 1776000Sroot { 17827088Sminshall register char *p, *q; 17927088Sminshall register char **c, **found; 18027088Sminshall register int nmatches, longest; 1816000Sroot 18227088Sminshall longest = 0; 18327088Sminshall nmatches = 0; 18427088Sminshall found = 0; 18527088Sminshall for (c = table; p = *c; c = (*next)(c)) { 18627088Sminshall for (q = name; *q == *p++; q++) 18727088Sminshall if (*q == 0) /* exact match? */ 18827088Sminshall return (c); 18927088Sminshall if (!*q) { /* the name was a prefix */ 19027088Sminshall if (q - name > longest) { 19127088Sminshall longest = q - name; 19227088Sminshall nmatches = 1; 19327088Sminshall found = c; 19427088Sminshall } else if (q - name == longest) 19527088Sminshall nmatches++; 1968377Ssam } 1976000Sroot } 19827088Sminshall if (nmatches > 1) 19927186Sminshall return Ambiguous(char **); 20027088Sminshall return (found); 2016000Sroot } 2026000Sroot 20327110Sminshall /* 20427110Sminshall * Make a character string into a number. 20527110Sminshall * 20627186Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 20727110Sminshall */ 2086000Sroot 20927110Sminshall special(s) 21027110Sminshall register char *s; 21127110Sminshall { 21227110Sminshall register char c; 21327110Sminshall char b; 21427110Sminshall 21527110Sminshall switch (*s) { 21627110Sminshall case '^': 21727110Sminshall b = *++s; 21827110Sminshall if (b == '?') { 21927228Sminshall c = b | 0x40; /* DEL */ 22027110Sminshall } else { 22127110Sminshall c = b & 0x1f; 22227110Sminshall } 22327110Sminshall break; 22427110Sminshall default: 22527110Sminshall c = *s; 22627110Sminshall break; 22727110Sminshall } 22827110Sminshall return c; 22927110Sminshall } 23027186Sminshall 23127186Sminshall /* 23227186Sminshall * Construct a control character sequence 23327186Sminshall * for a special character. 23427186Sminshall */ 23527186Sminshall char * 23627186Sminshall control(c) 23727186Sminshall register int c; 23827186Sminshall { 23927186Sminshall static char buf[3]; 24027186Sminshall 24127228Sminshall if (c == 0x7f) 24227186Sminshall return ("^?"); 24327186Sminshall if (c == '\377') { 24427186Sminshall return "off"; 24527186Sminshall } 24627186Sminshall if (c >= 0x20) { 24727186Sminshall buf[0] = c; 24827186Sminshall buf[1] = 0; 24927186Sminshall } else { 25027186Sminshall buf[0] = '^'; 25127186Sminshall buf[1] = '@'+c; 25227186Sminshall buf[2] = 0; 25327186Sminshall } 25427186Sminshall return (buf); 25527186Sminshall } 25627676Sminshall 25727676Sminshall 25827676Sminshall /* 25927676Sminshall * upcase() 26027676Sminshall * 26127676Sminshall * Upcase (in place) the argument. 26227676Sminshall */ 26327676Sminshall 26427676Sminshall void 26527676Sminshall upcase(argument) 26627676Sminshall register char *argument; 26727676Sminshall { 26827676Sminshall register int c; 26927676Sminshall 27027676Sminshall while (c = *argument) { 27127676Sminshall if (islower(c)) { 27227676Sminshall *argument = toupper(c); 27327676Sminshall } 27427676Sminshall argument++; 27527676Sminshall } 27627676Sminshall } 27727110Sminshall 27827110Sminshall /* 27927186Sminshall * Check to see if any out-of-band data exists on a socket (for 28027186Sminshall * Telnet "synch" processing). 28127186Sminshall */ 28227186Sminshall 28327186Sminshall int 28427186Sminshall stilloob(s) 28527186Sminshall int s; /* socket number */ 28627186Sminshall { 28727186Sminshall static struct timeval timeout = { 0 }; 28827186Sminshall fd_set excepts; 28927186Sminshall int value; 29027186Sminshall 29127186Sminshall do { 29227186Sminshall FD_ZERO(&excepts); 29327186Sminshall FD_SET(s, &excepts); 29427186Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 29527186Sminshall } while ((value == -1) && (errno = EINTR)); 29627186Sminshall 29727186Sminshall if (value < 0) { 29827186Sminshall perror("select"); 29927186Sminshall quit(); 30027186Sminshall } 30127186Sminshall if (FD_ISSET(s, &excepts)) { 30227186Sminshall return 1; 30327186Sminshall } else { 30427186Sminshall return 0; 30527186Sminshall } 30627186Sminshall } 30727186Sminshall 30827186Sminshall 30927186Sminshall /* 31027186Sminshall * netflush 31127186Sminshall * Send as much data as possible to the network, 31227186Sminshall * handling requests for urgent data. 31327186Sminshall */ 31427186Sminshall 31527186Sminshall 31627186Sminshall netflush(fd) 31727186Sminshall { 31827186Sminshall int n; 31927186Sminshall 32027186Sminshall if ((n = nfrontp - nbackp) > 0) { 32127186Sminshall if (!neturg) { 32227186Sminshall n = write(fd, nbackp, n); /* normal write */ 32327186Sminshall } else { 32427186Sminshall n = neturg - nbackp; 32527186Sminshall /* 32627186Sminshall * In 4.2 (and 4.3) systems, there is some question about 32727186Sminshall * what byte in a sendOOB operation is the "OOB" data. 32827186Sminshall * To make ourselves compatible, we only send ONE byte 32927186Sminshall * out of band, the one WE THINK should be OOB (though 33027186Sminshall * we really have more the TCP philosophy of urgent data 33127186Sminshall * rather than the Unix philosophy of OOB data). 33227186Sminshall */ 33327186Sminshall if (n > 1) { 33427186Sminshall n = send(fd, nbackp, n-1, 0); /* send URGENT all by itself */ 33527186Sminshall } else { 33627186Sminshall n = send(fd, nbackp, n, MSG_OOB); /* URGENT data */ 33727186Sminshall } 33827186Sminshall } 33927186Sminshall } 34027186Sminshall if (n < 0) { 34127186Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 34227186Sminshall setcommandmode(); 34327186Sminshall perror(hostname); 34427186Sminshall close(fd); 34527186Sminshall neturg = 0; 34627186Sminshall longjmp(peerdied, -1); 34727186Sminshall /*NOTREACHED*/ 34827186Sminshall } 34927186Sminshall n = 0; 35027186Sminshall } 35127186Sminshall if (netdata && n) { 35227186Sminshall Dump('>', nbackp, n); 35327186Sminshall } 35427186Sminshall nbackp += n; 35527186Sminshall if (nbackp >= neturg) { 35627186Sminshall neturg = 0; 35727186Sminshall } 35827186Sminshall if (nbackp == nfrontp) { 35927186Sminshall nbackp = nfrontp = netobuf; 36027186Sminshall } 36127186Sminshall } 36227261Sminshall 36327261Sminshall /* 36427261Sminshall * nextitem() 36527261Sminshall * 36627261Sminshall * Return the address of the next "item" in the TELNET data 36727261Sminshall * stream. This will be the address of the next character if 36827261Sminshall * the current address is a user data character, or it will 36927261Sminshall * be the address of the character following the TELNET command 37027261Sminshall * if the current address is a TELNET IAC ("I Am a Command") 37127261Sminshall * character. 37227261Sminshall */ 37327186Sminshall 37427261Sminshall char * 37527261Sminshall nextitem(current) 37627261Sminshall char *current; 37727261Sminshall { 37827261Sminshall if ((*current&0xff) != IAC) { 37927261Sminshall return current+1; 38027261Sminshall } 38127261Sminshall switch (*(current+1)&0xff) { 38227261Sminshall case DO: 38327261Sminshall case DONT: 38427261Sminshall case WILL: 38527261Sminshall case WONT: 38627261Sminshall return current+3; 38727261Sminshall case SB: /* loop forever looking for the SE */ 38827261Sminshall { 38927261Sminshall register char *look = current+2; 39027261Sminshall 39127261Sminshall for (;;) { 39227261Sminshall if ((*look++&0xff) == IAC) { 39327261Sminshall if ((*look++&0xff) == SE) { 39427261Sminshall return look; 39527261Sminshall } 39627261Sminshall } 39727261Sminshall } 39827261Sminshall } 39927261Sminshall default: 40027261Sminshall return current+2; 40127261Sminshall } 40227261Sminshall } 40327186Sminshall /* 40427261Sminshall * netclear() 40527261Sminshall * 40627261Sminshall * We are about to do a TELNET SYNCH operation. Clear 40727261Sminshall * the path to the network. 40827261Sminshall * 40927261Sminshall * Things are a bit tricky since we may have sent the first 41027261Sminshall * byte or so of a previous TELNET command into the network. 41127261Sminshall * So, we have to scan the network buffer from the beginning 41227261Sminshall * until we are up to where we want to be. 41327261Sminshall * 41427261Sminshall * A side effect of what we do, just to keep things 41527261Sminshall * simple, is to clear the urgent data pointer. The principal 41627261Sminshall * caller should be setting the urgent data pointer AFTER calling 41727261Sminshall * us in any case. 41827261Sminshall */ 41927261Sminshall 42027261Sminshall netclear() 42127261Sminshall { 42227261Sminshall register char *thisitem, *next; 42327261Sminshall char *good; 42427261Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 42527261Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 42627261Sminshall 42727261Sminshall thisitem = netobuf; 42827261Sminshall 42927261Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 43027261Sminshall thisitem = next; 43127261Sminshall } 43227261Sminshall 43327261Sminshall /* Now, thisitem is first before/at boundary. */ 43427261Sminshall 43527261Sminshall good = netobuf; /* where the good bytes go */ 43627261Sminshall 43727261Sminshall while (nfrontp > thisitem) { 43827261Sminshall if (wewant(thisitem)) { 43927261Sminshall int length; 44027261Sminshall 44127261Sminshall next = thisitem; 44227261Sminshall do { 44327261Sminshall next = nextitem(next); 44427261Sminshall } while (wewant(next) && (nfrontp > next)); 44527261Sminshall length = next-thisitem; 44627261Sminshall bcopy(thisitem, good, length); 44727261Sminshall good += length; 44827261Sminshall thisitem = next; 44927261Sminshall } else { 45027261Sminshall thisitem = nextitem(thisitem); 45127261Sminshall } 45227261Sminshall } 45327261Sminshall 45427261Sminshall nbackp = netobuf; 45527261Sminshall nfrontp = good; /* next byte to be sent */ 45627261Sminshall neturg = 0; 45727261Sminshall } 45827261Sminshall 45927261Sminshall /* 46027186Sminshall * Send as much data as possible to the terminal. 46127186Sminshall */ 46227186Sminshall 46327186Sminshall 46427186Sminshall ttyflush() 46527186Sminshall { 46627186Sminshall int n; 46727186Sminshall 46827186Sminshall if ((n = tfrontp - tbackp) > 0) { 46927228Sminshall if (!(SYNCHing||flushout)) { 47027186Sminshall n = write(tout, tbackp, n); 47127186Sminshall } else { 47227186Sminshall ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 47327228Sminshall /* we leave 'n' alone! */ 47427186Sminshall } 47527186Sminshall } 47627186Sminshall if (n < 0) { 47727186Sminshall return; 47827186Sminshall } 47927186Sminshall tbackp += n; 48027186Sminshall if (tbackp == tfrontp) { 48127186Sminshall tbackp = tfrontp = ttyobuf; 48227186Sminshall } 48327186Sminshall } 48427186Sminshall 48527186Sminshall /* 48627110Sminshall * Various signal handling routines. 48727110Sminshall */ 48827110Sminshall 48927110Sminshall deadpeer() 49027110Sminshall { 49127110Sminshall setcommandmode(); 49227110Sminshall longjmp(peerdied, -1); 49327110Sminshall } 49427110Sminshall 49527110Sminshall intr() 49627110Sminshall { 49727261Sminshall if (localchars) { 49827110Sminshall intp(); 49927110Sminshall return; 50027110Sminshall } 50127110Sminshall setcommandmode(); 50227110Sminshall longjmp(toplevel, -1); 50327110Sminshall } 50427110Sminshall 50527110Sminshall intr2() 50627110Sminshall { 50727261Sminshall if (localchars) { 50827110Sminshall sendbrk(); 50927110Sminshall return; 51027110Sminshall } 51127110Sminshall } 51227110Sminshall 51327110Sminshall doescape() 51427110Sminshall { 51527110Sminshall command(0); 51627110Sminshall } 51727110Sminshall 51827110Sminshall /* 51927186Sminshall * The following are routines used to print out debugging information. 52027186Sminshall */ 52127186Sminshall 52227186Sminshall 52327186Sminshall static 52427186Sminshall Dump(direction, buffer, length) 52527186Sminshall char direction; 52627186Sminshall char *buffer; 52727186Sminshall int length; 52827186Sminshall { 52927186Sminshall # define BYTES_PER_LINE 32 53027186Sminshall # define min(x,y) ((x<y)? x:y) 53127186Sminshall char *pThis; 53227186Sminshall int offset; 53327186Sminshall 53427186Sminshall offset = 0; 53527186Sminshall 53627186Sminshall while (length) { 53727186Sminshall /* print one line */ 53827186Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 53927186Sminshall pThis = buffer; 54027186Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 54127186Sminshall while (pThis < buffer) { 54227186Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 54327186Sminshall pThis++; 54427186Sminshall } 54527186Sminshall fprintf(NetTrace, "\n"); 54627186Sminshall length -= BYTES_PER_LINE; 54727186Sminshall offset += BYTES_PER_LINE; 54827186Sminshall if (length < 0) { 54927186Sminshall return; 55027186Sminshall } 55127186Sminshall /* find next unique line */ 55227186Sminshall } 55327186Sminshall } 55427186Sminshall 55527186Sminshall 55627186Sminshall /*VARARGS*/ 55727186Sminshall printoption(direction, fmt, option, what) 55827186Sminshall char *direction, *fmt; 55927186Sminshall int option, what; 56027186Sminshall { 56127186Sminshall if (!showoptions) 56227186Sminshall return; 56327676Sminshall printf("%s ", direction+1); 56427186Sminshall if (fmt == doopt) 56527186Sminshall fmt = "do"; 56627186Sminshall else if (fmt == dont) 56727186Sminshall fmt = "dont"; 56827186Sminshall else if (fmt == will) 56927186Sminshall fmt = "will"; 57027186Sminshall else if (fmt == wont) 57127186Sminshall fmt = "wont"; 57227186Sminshall else 57327186Sminshall fmt = "???"; 57427676Sminshall if (option < (sizeof telopts/sizeof telopts[0])) 57527186Sminshall printf("%s %s", fmt, telopts[option]); 57627186Sminshall else 57727186Sminshall printf("%s %d", fmt, option); 57827186Sminshall if (*direction == '<') { 57927186Sminshall printf("\r\n"); 58027186Sminshall return; 58127186Sminshall } 58227186Sminshall printf(" (%s)\r\n", what ? "reply" : "don't reply"); 58327186Sminshall } 58427186Sminshall 58527186Sminshall /* 58627110Sminshall * Mode - set up terminal to a specific mode. 58727110Sminshall */ 58827110Sminshall 5899972Ssam 5906000Sroot mode(f) 5916000Sroot register int f; 5926000Sroot { 5938378Ssam static int prevmode = 0; 59413076Ssam struct tchars *tc; 59513076Ssam struct ltchars *ltc; 59613076Ssam struct sgttyb sb; 59713076Ssam int onoff, old; 59827228Sminshall struct tchars notc2; 59927228Sminshall struct ltchars noltc2; 60027228Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 60127228Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 6026000Sroot 60327110Sminshall globalmode = f; 6048378Ssam if (prevmode == f) 60527186Sminshall return; 6068378Ssam old = prevmode; 6078378Ssam prevmode = f; 60827110Sminshall sb = nttyb; 6096000Sroot switch (f) { 6108378Ssam 6116000Sroot case 0: 6126000Sroot onoff = 0; 6139972Ssam tc = &otc; 61413076Ssam ltc = &oltc; 6156000Sroot break; 6166000Sroot 61727110Sminshall case 1: /* remote character processing, remote echo */ 61827110Sminshall case 2: /* remote character processing, local echo */ 61913076Ssam sb.sg_flags |= CBREAK; 6208378Ssam if (f == 1) 62113076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 6228378Ssam else 62313076Ssam sb.sg_flags |= ECHO|CRMOD; 62413076Ssam sb.sg_erase = sb.sg_kill = -1; 6259972Ssam tc = ¬c; 62627110Sminshall /* 62727110Sminshall * If user hasn't specified one way or the other, 62827110Sminshall * then default to not trapping signals. 62927110Sminshall */ 63027261Sminshall if (!donelclchars) { 63127261Sminshall localchars = 0; 63227228Sminshall } 63327261Sminshall if (localchars) { 63427110Sminshall notc2 = notc; 63527110Sminshall notc2.t_intrc = ntc.t_intrc; 63627110Sminshall notc2.t_quitc = ntc.t_quitc; 63727110Sminshall tc = ¬c2; 63827110Sminshall } else 63927110Sminshall tc = ¬c; 64013076Ssam ltc = &noltc; 6416000Sroot onoff = 1; 6429972Ssam break; 64327110Sminshall case 3: /* local character processing, remote echo */ 64427110Sminshall case 4: /* local character processing, local echo */ 64527110Sminshall case 5: /* local character processing, no echo */ 64627110Sminshall sb.sg_flags &= ~CBREAK; 64727110Sminshall sb.sg_flags |= CRMOD; 64827110Sminshall if (f == 4) 64927110Sminshall sb.sg_flags |= ECHO; 65027110Sminshall else 65127110Sminshall sb.sg_flags &= ~ECHO; 65227228Sminshall notc2 = ntc; 65327228Sminshall tc = ¬c2; 65427228Sminshall noltc2 = oltc; 65527228Sminshall ltc = &noltc2; 65627110Sminshall /* 65727110Sminshall * If user hasn't specified one way or the other, 65827110Sminshall * then default to trapping signals. 65927110Sminshall */ 66027261Sminshall if (!donelclchars) { 66127261Sminshall localchars = 1; 66227228Sminshall } 66327261Sminshall if (localchars) { 66427228Sminshall notc2.t_brkc = nltc.t_flushc; 66527228Sminshall noltc2.t_flushc = -1; 66627228Sminshall } else { 66727110Sminshall notc2.t_intrc = notc2.t_quitc = -1; 66827110Sminshall } 66927110Sminshall noltc2.t_suspc = escape; 67027110Sminshall noltc2.t_dsuspc = -1; 67127110Sminshall onoff = 1; 67227110Sminshall break; 6739972Ssam 6749972Ssam default: 6759972Ssam return; 6766000Sroot } 67713076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 67813076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 67913076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 68027186Sminshall ioctl(fileno(stdin), FIONBIO, (char *)&onoff); 68127186Sminshall ioctl(fileno(stdout), FIONBIO, (char *)&onoff); 68227110Sminshall if (f >= 3) 68327110Sminshall signal(SIGTSTP, doescape); 68427110Sminshall else if (old >= 3) { 68527110Sminshall signal(SIGTSTP, SIG_DFL); 68627110Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 68727110Sminshall } 6886000Sroot } 68927186Sminshall 69027110Sminshall /* 69127110Sminshall * These routines decides on what the mode should be (based on the values 69227110Sminshall * of various global variables). 69327110Sminshall */ 69427110Sminshall 69527178Sminshall char *modedescriptions[] = { 69627178Sminshall "telnet command mode", /* 0 */ 69727178Sminshall "character-at-a-time mode", /* 1 */ 69827178Sminshall "character-at-a-time mode (local echo)", /* 2 */ 69927178Sminshall "line-by-line mode (remote echo)", /* 3 */ 70027178Sminshall "line-by-line mode", /* 4 */ 70127178Sminshall "line-by-line mode (local echoing suppressed)", /* 5 */ 70227178Sminshall }; 70327178Sminshall 70427178Sminshall getconnmode() 70527110Sminshall { 70627110Sminshall static char newmode[8] = { 4, 5, 3, 3, 2, 2, 1, 1 }; 70727186Sminshall int modeindex = 0; 70827110Sminshall 70927110Sminshall if (hisopts[TELOPT_ECHO]) { 71027186Sminshall modeindex += 2; 71127110Sminshall } 71227110Sminshall if (hisopts[TELOPT_SGA]) { 71327186Sminshall modeindex += 4; 71427110Sminshall } 71527186Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 71627186Sminshall modeindex += 1; 71727110Sminshall } 71827186Sminshall return newmode[modeindex]; 71927110Sminshall } 72027110Sminshall 72127178Sminshall setconnmode() 72227178Sminshall { 72327178Sminshall mode(getconnmode()); 72427178Sminshall } 72527110Sminshall 72627178Sminshall 72727110Sminshall setcommandmode() 72827110Sminshall { 72927110Sminshall mode(0); 73027110Sminshall } 73127110Sminshall 7326000Sroot char sibuf[BUFSIZ], *sbp; 7336000Sroot char tibuf[BUFSIZ], *tbp; 7346000Sroot int scc, tcc; 7356000Sroot 73627228Sminshall 7376000Sroot /* 7386000Sroot * Select from tty and network... 7396000Sroot */ 74027088Sminshall telnet() 7416000Sroot { 7426000Sroot register int c; 74327088Sminshall int tin = fileno(stdin); 7446000Sroot int on = 1; 74527261Sminshall fd_set ibits, obits, xbits; 7466000Sroot 74727088Sminshall tout = fileno(stdout); 74827110Sminshall setconnmode(); 74927228Sminshall scc = 0; 75027228Sminshall tcc = 0; 75127261Sminshall FD_ZERO(&ibits); 75227261Sminshall FD_ZERO(&obits); 75327261Sminshall FD_ZERO(&xbits); 75427261Sminshall 75527186Sminshall ioctl(net, FIONBIO, (char *)&on); 75627676Sminshall #if defined(SO_OOBINLINE) 75727676Sminshall setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); 75827676Sminshall #endif /* defined(SO_OOBINLINE) */ 75927676Sminshall if (telnetport) { 76027676Sminshall if (!hisopts[TELOPT_SGA]) { 76127676Sminshall willoption(TELOPT_SGA, 0); 76227676Sminshall } 76327676Sminshall if (!myopts[TELOPT_TTYPE]) { 76427676Sminshall dooption(TELOPT_TTYPE, 0); 76527676Sminshall } 76627088Sminshall } 7676000Sroot for (;;) { 76827110Sminshall if (scc < 0 && tcc < 0) { 7696000Sroot break; 77027110Sminshall } 77127110Sminshall 77227228Sminshall if (((globalmode < 4) || flushline) && NETBYTES()) { 77327110Sminshall FD_SET(net, &obits); 77427088Sminshall } else { 77527110Sminshall FD_SET(tin, &ibits); 77627088Sminshall } 77727228Sminshall if (TTYBYTES()) { 77827110Sminshall FD_SET(tout, &obits); 77927110Sminshall } else { 78027110Sminshall FD_SET(net, &ibits); 78127110Sminshall } 78227186Sminshall if (!SYNCHing) { 78327110Sminshall FD_SET(net, &xbits); 78427110Sminshall } 78527186Sminshall if ((c = select(16, &ibits, &obits, &xbits, 78627186Sminshall (struct timeval *)0)) < 1) { 78727110Sminshall if (c == -1) { 78827110Sminshall /* 78927110Sminshall * we can get EINTR if we are in line mode, 79027110Sminshall * and the user does an escape (TSTP), or 79127110Sminshall * some other signal generator. 79227110Sminshall */ 79327110Sminshall if (errno == EINTR) { 79427110Sminshall continue; 79527110Sminshall } 79627110Sminshall } 7976000Sroot sleep(5); 7986000Sroot continue; 7996000Sroot } 8006000Sroot 8016000Sroot /* 80227088Sminshall * Any urgent data? 80327088Sminshall */ 80427110Sminshall if (FD_ISSET(net, &xbits)) { 80527261Sminshall FD_CLR(net, &xbits); 80627186Sminshall SYNCHing = 1; 80727088Sminshall ttyflush(); /* flush already enqueued data */ 80827088Sminshall } 80927088Sminshall 81027088Sminshall /* 8116000Sroot * Something to read from the network... 8126000Sroot */ 81327110Sminshall if (FD_ISSET(net, &ibits)) { 81427228Sminshall int canread; 81527228Sminshall 81627261Sminshall FD_CLR(net, &ibits); 81727228Sminshall if (scc == 0) { 81827228Sminshall sbp = sibuf; 81927228Sminshall } 82027228Sminshall canread = sibuf + sizeof sibuf - sbp; 82127676Sminshall #if !defined(SO_OOBINLINE) 82227178Sminshall /* 82327178Sminshall * In 4.2 (and some early 4.3) systems, the 82427178Sminshall * OOB indication and data handling in the kernel 82527178Sminshall * is such that if two separate TCP Urgent requests 82627178Sminshall * come in, one byte of TCP data will be overlaid. 82727178Sminshall * This is fatal for Telnet, but we try to live 82827178Sminshall * with it. 82927178Sminshall * 83027178Sminshall * In addition, in 4.2 (and...), a special protocol 83127178Sminshall * is needed to pick up the TCP Urgent data in 83227178Sminshall * the correct sequence. 83327178Sminshall * 83427178Sminshall * What we do is: if we think we are in urgent 83527178Sminshall * mode, we look to see if we are "at the mark". 83627178Sminshall * If we are, we do an OOB receive. If we run 83727178Sminshall * this twice, we will do the OOB receive twice, 83827178Sminshall * but the second will fail, since the second 83927178Sminshall * time we were "at the mark", but there wasn't 84027178Sminshall * any data there (the kernel doesn't reset 84127178Sminshall * "at the mark" until we do a normal read). 84227178Sminshall * Once we've read the OOB data, we go ahead 84327178Sminshall * and do normal reads. 84427178Sminshall * 84527178Sminshall * There is also another problem, which is that 84627178Sminshall * since the OOB byte we read doesn't put us 84727178Sminshall * out of OOB state, and since that byte is most 84827178Sminshall * likely the TELNET DM (data mark), we would 84927186Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 85027178Sminshall * So, clocks to the rescue. If we've "just" 85127178Sminshall * received a DM, then we test for the 85227178Sminshall * presence of OOB data when the receive OOB 85327178Sminshall * fails (and AFTER we did the normal mode read 85427178Sminshall * to clear "at the mark"). 85527178Sminshall */ 85627186Sminshall if (SYNCHing) { 85727178Sminshall int atmark; 85827178Sminshall 85927186Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 86027178Sminshall if (atmark) { 86127228Sminshall c = recv(net, sibuf, canread, MSG_OOB); 86227228Sminshall if ((c == -1) && (errno == EINVAL)) { 86327228Sminshall c = read(net, sibuf, canread); 86427186Sminshall if (clocks.didnetreceive < clocks.gotDM) { 86527186Sminshall SYNCHing = stilloob(net); 86627021Sminshall } 86727178Sminshall } 86827178Sminshall } else { 86927228Sminshall c = read(net, sibuf, canread); 8706000Sroot } 87127178Sminshall } else { 87227228Sminshall c = read(net, sibuf, canread); 87327178Sminshall } 87427178Sminshall settimer(didnetreceive); 87527676Sminshall #else /* !defined(SO_OOBINLINE) */ 87627228Sminshall c = read(net, sbp, canread); 87727676Sminshall #endif /* !defined(SO_OOBINLINE) */ 87827228Sminshall if (c < 0 && errno == EWOULDBLOCK) { 87927228Sminshall c = 0; 88027228Sminshall } else if (c <= 0) { 88127228Sminshall break; 88227178Sminshall } 88327228Sminshall if (netdata) { 88427228Sminshall Dump('<', sbp, c); 88527228Sminshall } 88627228Sminshall scc += c; 8876000Sroot } 8886000Sroot 8896000Sroot /* 8906000Sroot * Something to read from the tty... 8916000Sroot */ 89227110Sminshall if (FD_ISSET(tin, &ibits)) { 89327261Sminshall FD_CLR(tin, &ibits); 89427228Sminshall if (tcc == 0) { 89527228Sminshall tbp = tibuf; /* nothing left, reset */ 8966000Sroot } 89727228Sminshall c = read(tin, tbp, tibuf+sizeof tibuf - tbp); 89827228Sminshall if (c < 0 && errno == EWOULDBLOCK) { 89927228Sminshall c = 0; 90027676Sminshall } else { 90127676Sminshall /* EOF detection for line mode!!!! */ 90227676Sminshall if (c == 0 && globalmode >= 3) { 90327676Sminshall /* must be an EOF... */ 90427676Sminshall *tbp = ntc.t_eofc; 90527676Sminshall c = 1; 90627676Sminshall } 90727676Sminshall if (c <= 0) { 90827676Sminshall tcc = c; 90927676Sminshall break; 91027676Sminshall } 91127228Sminshall } 91227228Sminshall tcc += c; 9136000Sroot } 9146000Sroot 9156000Sroot while (tcc > 0) { 91627186Sminshall register int sc; 9176000Sroot 91827228Sminshall if (NETROOM() < 2) { 91927110Sminshall flushline = 1; 9206000Sroot break; 92127110Sminshall } 92227186Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 92327186Sminshall if (sc == escape) { 9246000Sroot command(0); 9256000Sroot tcc = 0; 92627110Sminshall flushline = 1; 9276000Sroot break; 92827261Sminshall } else if ((globalmode >= 4) && (sc == echoc)) { 92927110Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 93027110Sminshall tbp++; 93127110Sminshall tcc--; 93227110Sminshall } else { 93327110Sminshall dontlecho = !dontlecho; 93427110Sminshall settimer(echotoggle); 93527110Sminshall setconnmode(); 93627110Sminshall tcc = 0; 93727110Sminshall flushline = 1; 93827110Sminshall break; 93927110Sminshall } 9406000Sroot } 94127261Sminshall if (localchars) { 94227186Sminshall if (sc == ntc.t_intrc) { 94327110Sminshall intp(); 94427110Sminshall break; 94527186Sminshall } else if (sc == ntc.t_quitc) { 94627110Sminshall sendbrk(); 94727110Sminshall break; 94827228Sminshall } else if (sc == nltc.t_flushc) { 94927228Sminshall NET2ADD(IAC, AO); 95027228Sminshall if (autoflush) { 95127228Sminshall doflush(); 95227228Sminshall } 95327228Sminshall break; 95427110Sminshall } else if (globalmode > 2) { 95527110Sminshall ; 95627186Sminshall } else if (sc == nttyb.sg_kill) { 95727110Sminshall NET2ADD(IAC, EL); 95827110Sminshall break; 95927186Sminshall } else if (sc == nttyb.sg_erase) { 96027110Sminshall NET2ADD(IAC, EC); 96127110Sminshall break; 96227110Sminshall } 96327110Sminshall } 96417922Sralph switch (c) { 96517922Sralph case '\n': 96627021Sminshall /* 96727021Sminshall * If echoing is happening locally, 96827021Sminshall * then a newline (unix) is CRLF (TELNET). 96927021Sminshall */ 97027088Sminshall if (!hisopts[TELOPT_ECHO]) { 97127088Sminshall NETADD('\r'); 97227088Sminshall } 97327088Sminshall NETADD('\n'); 97427110Sminshall flushline = 1; 97517922Sralph break; 97617922Sralph case '\r': 97727088Sminshall NET2ADD('\r', '\0'); 97827110Sminshall flushline = 1; 97917922Sralph break; 98017922Sralph case IAC: 98127088Sminshall NET2ADD(IAC, IAC); 98227021Sminshall break; 98317922Sralph default: 98427088Sminshall NETADD(c); 98517922Sralph break; 98617922Sralph } 9876000Sroot } 98827110Sminshall if (((globalmode < 4) || flushline) && 98927228Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 99027261Sminshall FD_CLR(net, &obits); 99127088Sminshall netflush(net); 99227110Sminshall } 9936000Sroot if (scc > 0) 9946000Sroot telrcv(); 99527261Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) { 99627261Sminshall FD_CLR(tout, &obits); 99727088Sminshall ttyflush(); 99827261Sminshall } 9996000Sroot } 100027110Sminshall setcommandmode(); 10016000Sroot } 100227110Sminshall 10036000Sroot /* 10046000Sroot * Telnet receiver states for fsm 10056000Sroot */ 10066000Sroot #define TS_DATA 0 10076000Sroot #define TS_IAC 1 10086000Sroot #define TS_WILL 2 10096000Sroot #define TS_WONT 3 10106000Sroot #define TS_DO 4 10116000Sroot #define TS_DONT 5 101227021Sminshall #define TS_CR 6 101327676Sminshall #define TS_SB 7 /* sub-option collection */ 101427676Sminshall #define TS_SE 8 /* looking for sub-option end */ 10156000Sroot 10166000Sroot telrcv() 10176000Sroot { 10186000Sroot register int c; 10196000Sroot static int state = TS_DATA; 10206000Sroot 102127228Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 102227186Sminshall c = *sbp++ & 0xff, scc--; 10236000Sroot switch (state) { 10246000Sroot 102527021Sminshall case TS_CR: 102627021Sminshall state = TS_DATA; 102727228Sminshall if (c == '\0') { 102827228Sminshall break; /* Ignore \0 after CR */ 102927228Sminshall } else if (c == '\n') { 103027228Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 103127228Sminshall TTYADD(c); 103227228Sminshall } 103327228Sminshall break; 103427021Sminshall } 103527228Sminshall /* Else, fall through */ 103627021Sminshall 10376000Sroot case TS_DATA: 10389972Ssam if (c == IAC) { 10396000Sroot state = TS_IAC; 10409972Ssam continue; 10419972Ssam } 104227228Sminshall /* 104327228Sminshall * The 'crmod' hack (see following) is needed 104427228Sminshall * since we can't * set CRMOD on output only. 104527228Sminshall * Machines like MULTICS like to send \r without 104627228Sminshall * \n; since we must turn off CRMOD to get proper 104727228Sminshall * input, the mapping is done here (sigh). 104827228Sminshall */ 104927021Sminshall if (c == '\r') { 105027021Sminshall if (scc > 0) { 105127186Sminshall c = *sbp&0xff; 105227021Sminshall if (c == 0) { 105327021Sminshall sbp++, scc--; 105427228Sminshall /* a "true" CR */ 105527088Sminshall TTYADD('\r'); 105627021Sminshall } else if (!hisopts[TELOPT_ECHO] && 105727021Sminshall (c == '\n')) { 105827021Sminshall sbp++, scc--; 105927088Sminshall TTYADD('\n'); 106027021Sminshall } else { 106127088Sminshall TTYADD('\r'); 106227228Sminshall if (crmod) { 106327228Sminshall TTYADD('\n'); 106427228Sminshall } 106527021Sminshall } 106627021Sminshall } else { 106727021Sminshall state = TS_CR; 106827088Sminshall TTYADD('\r'); 106927228Sminshall if (crmod) { 107027228Sminshall TTYADD('\n'); 107127228Sminshall } 107227021Sminshall } 107327021Sminshall } else { 107427088Sminshall TTYADD(c); 107527021Sminshall } 10766000Sroot continue; 10776000Sroot 10786000Sroot case TS_IAC: 10796000Sroot switch (c) { 10806000Sroot 10816000Sroot case WILL: 10826000Sroot state = TS_WILL; 10836000Sroot continue; 10846000Sroot 10856000Sroot case WONT: 10866000Sroot state = TS_WONT; 10876000Sroot continue; 10886000Sroot 10896000Sroot case DO: 10906000Sroot state = TS_DO; 10916000Sroot continue; 10926000Sroot 10936000Sroot case DONT: 10946000Sroot state = TS_DONT; 10956000Sroot continue; 10966000Sroot 10976000Sroot case DM: 109827088Sminshall /* 109927088Sminshall * We may have missed an urgent notification, 110027088Sminshall * so make sure we flush whatever is in the 110127088Sminshall * buffer currently. 110227088Sminshall */ 110327186Sminshall SYNCHing = 1; 110427088Sminshall ttyflush(); 110527186Sminshall SYNCHing = stilloob(net); 110627178Sminshall settimer(gotDM); 11076000Sroot break; 11086000Sroot 11096000Sroot case NOP: 11106000Sroot case GA: 11116000Sroot break; 11126000Sroot 111327676Sminshall case SB: 111427676Sminshall SB_CLEAR(); 111527676Sminshall state = TS_SB; 111627676Sminshall continue; 111727676Sminshall 11186000Sroot default: 11196000Sroot break; 11206000Sroot } 11216000Sroot state = TS_DATA; 11226000Sroot continue; 11236000Sroot 11246000Sroot case TS_WILL: 112527676Sminshall printoption(">RCVD", will, c, !hisopts[c]); 112627110Sminshall if (c == TELOPT_TM) { 112727110Sminshall if (flushout) { 112827186Sminshall flushout = 0; 112927110Sminshall } 113027110Sminshall } else if (!hisopts[c]) { 113127676Sminshall willoption(c, 1); 113227110Sminshall } 11336000Sroot state = TS_DATA; 11346000Sroot continue; 11356000Sroot 11366000Sroot case TS_WONT: 113727676Sminshall printoption(">RCVD", wont, c, hisopts[c]); 113827110Sminshall if (c == TELOPT_TM) { 113927110Sminshall if (flushout) { 114027186Sminshall flushout = 0; 114127110Sminshall } 114227110Sminshall } else if (hisopts[c]) { 114327676Sminshall wontoption(c, 1); 114427110Sminshall } 11456000Sroot state = TS_DATA; 11466000Sroot continue; 11476000Sroot 11486000Sroot case TS_DO: 114927676Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 11506000Sroot if (!myopts[c]) 11516000Sroot dooption(c); 11526000Sroot state = TS_DATA; 11536000Sroot continue; 11546000Sroot 11556000Sroot case TS_DONT: 115627676Sminshall printoption(">RCVD", dont, c, myopts[c]); 11576000Sroot if (myopts[c]) { 11586000Sroot myopts[c] = 0; 11596000Sroot sprintf(nfrontp, wont, c); 11608378Ssam nfrontp += sizeof (wont) - 2; 116127110Sminshall flushline = 1; 116227110Sminshall setconnmode(); /* set new tty mode (maybe) */ 116327676Sminshall printoption(">SENT", wont, c); 11646000Sroot } 11656000Sroot state = TS_DATA; 11666000Sroot continue; 116727676Sminshall case TS_SB: 116827676Sminshall if (c == IAC) { 116927676Sminshall state = TS_SE; 117027676Sminshall } else { 117127676Sminshall SB_ACCUM(c); 117227676Sminshall } 117327676Sminshall continue; 117427676Sminshall 117527676Sminshall case TS_SE: 117627676Sminshall if (c != SE) { 117727676Sminshall if (c != IAC) { 117827676Sminshall SB_ACCUM(IAC); 117927676Sminshall } 118027676Sminshall SB_ACCUM(c); 118127676Sminshall state = TS_SB; 118227676Sminshall } else { 118327676Sminshall SB_TERM(); 118427676Sminshall suboption(); /* handle sub-option */ 118527676Sminshall state = TS_DATA; 118627676Sminshall } 11876000Sroot } 11886000Sroot } 11896000Sroot } 119027110Sminshall 119127676Sminshall willoption(option, reply) 119227676Sminshall int option, reply; 11936000Sroot { 11946000Sroot char *fmt; 11956000Sroot 11966000Sroot switch (option) { 11976000Sroot 11986000Sroot case TELOPT_ECHO: 11996000Sroot case TELOPT_SGA: 120027110Sminshall settimer(modenegotiated); 12016000Sroot hisopts[option] = 1; 12026000Sroot fmt = doopt; 120327110Sminshall setconnmode(); /* possibly set new tty mode */ 12046000Sroot break; 12056000Sroot 12066000Sroot case TELOPT_TM: 120727110Sminshall return; /* Never reply to TM will's/wont's */ 12086000Sroot 12096000Sroot default: 12106000Sroot fmt = dont; 12116000Sroot break; 12126000Sroot } 12136024Ssam sprintf(nfrontp, fmt, option); 12148378Ssam nfrontp += sizeof (dont) - 2; 121527676Sminshall if (reply) 121627676Sminshall printoption(">SENT", fmt, option); 121727676Sminshall else 121827676Sminshall printoption("<SENT", fmt, option); 12196000Sroot } 12206000Sroot 122127676Sminshall wontoption(option, reply) 122227676Sminshall int option, reply; 12236000Sroot { 12246000Sroot char *fmt; 12256000Sroot 12266000Sroot switch (option) { 12276000Sroot 12286000Sroot case TELOPT_ECHO: 12296000Sroot case TELOPT_SGA: 123027110Sminshall settimer(modenegotiated); 12316000Sroot hisopts[option] = 0; 12326000Sroot fmt = dont; 123327110Sminshall setconnmode(); /* Set new tty mode */ 12346000Sroot break; 12356000Sroot 123627110Sminshall case TELOPT_TM: 123727110Sminshall return; /* Never reply to TM will's/wont's */ 123827110Sminshall 12396000Sroot default: 12406000Sroot fmt = dont; 12416000Sroot } 12426000Sroot sprintf(nfrontp, fmt, option); 12438378Ssam nfrontp += sizeof (doopt) - 2; 124427676Sminshall if (reply) 124527676Sminshall printoption(">SENT", fmt, option); 124627676Sminshall else 124727676Sminshall printoption("<SENT", fmt, option); 12486000Sroot } 12496000Sroot 12506000Sroot dooption(option) 12516000Sroot int option; 12526000Sroot { 12536000Sroot char *fmt; 12546000Sroot 12556000Sroot switch (option) { 12566000Sroot 12576000Sroot case TELOPT_TM: 125813231Ssam fmt = will; 125913231Ssam break; 126013231Ssam 126127676Sminshall case TELOPT_TTYPE: /* terminal type option */ 126227110Sminshall case TELOPT_SGA: /* no big deal */ 12636000Sroot fmt = will; 126427110Sminshall myopts[option] = 1; 12656000Sroot break; 12666000Sroot 126727110Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 12686000Sroot default: 12696000Sroot fmt = wont; 12706000Sroot break; 12716000Sroot } 12726000Sroot sprintf(nfrontp, fmt, option); 12738378Ssam nfrontp += sizeof (doopt) - 2; 127427676Sminshall printoption(">SENT", fmt, option); 12756000Sroot } 127627676Sminshall 127727676Sminshall /* 127827676Sminshall * suboption() 127927676Sminshall * 128027676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 128127676Sminshall * side. 128227676Sminshall * 128327676Sminshall * Currently we recognize: 128427676Sminshall * 128527676Sminshall * Terminal type, send request. 128627676Sminshall */ 128727676Sminshall 128827676Sminshall suboption() 128927676Sminshall { 129027676Sminshall switch (subbuffer[0]&0xff) { 129127676Sminshall case TELOPT_TTYPE: 129227676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 129327676Sminshall ; 129427676Sminshall } else { 129527676Sminshall char *name; 129627676Sminshall char namebuf[41]; 129727676Sminshall char *getenv(); 129827676Sminshall int len; 129927676Sminshall 130027676Sminshall name = getenv("TERM"); 130127676Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 130227676Sminshall name = "UNKNOWN"; 130327676Sminshall } 130427676Sminshall if ((len + 4+2) < NETROOM()) { 130527676Sminshall strcpy(namebuf, name); 130627676Sminshall upcase(namebuf); 130727676Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 130827676Sminshall TELQUAL_IS, namebuf, IAC, SE); 130927676Sminshall nfrontp += 4+strlen(namebuf)+2; 131027676Sminshall } 131127676Sminshall } 131227676Sminshall 131327676Sminshall default: 131427676Sminshall break; 131527676Sminshall } 131627676Sminshall } 131727110Sminshall 13186000Sroot /* 131927088Sminshall * The following are data structures and routines for 132027088Sminshall * the "send" command. 132127088Sminshall * 132227088Sminshall */ 132327088Sminshall 132427088Sminshall struct sendlist { 132527088Sminshall char *name; /* How user refers to it (case independent) */ 132627088Sminshall int what; /* Character to be sent (<0 ==> special) */ 132727088Sminshall char *help; /* Help information (0 ==> no help) */ 132827088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 132927088Sminshall }; 133027088Sminshall 133127186Sminshall /*ARGSUSED*/ 133227088Sminshall dosynch(s) 133327088Sminshall struct sendlist *s; 133427088Sminshall { 133527261Sminshall netclear(); /* clear the path to the network */ 133627088Sminshall NET2ADD(IAC, DM); 133727186Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 133827088Sminshall } 133927088Sminshall 134027228Sminshall doflush() 134127228Sminshall { 134227228Sminshall NET2ADD(IAC, DO); 134327228Sminshall NETADD(TELOPT_TM); 134427228Sminshall flushline = 1; 134527228Sminshall flushout = 1; 134627228Sminshall ttyflush(); 134727676Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 134827676Sminshall printoption("<SENT", doopt, TELOPT_TM); 134927228Sminshall } 135027228Sminshall 135127088Sminshall intp() 135227088Sminshall { 135327110Sminshall NET2ADD(IAC, IP); 135427228Sminshall if (autoflush) { 135527228Sminshall doflush(); 135627228Sminshall } 135727228Sminshall if (autosynch) { 135827228Sminshall dosynch(); 135927228Sminshall } 136027088Sminshall } 136127088Sminshall 136227110Sminshall sendbrk() 136327110Sminshall { 136427186Sminshall NET2ADD(IAC, BREAK); 136527228Sminshall if (autoflush) { 136627228Sminshall doflush(); 136727228Sminshall } 136827228Sminshall if (autosynch) { 136927228Sminshall dosynch(); 137027228Sminshall } 137127110Sminshall } 137227088Sminshall 137327110Sminshall 137427088Sminshall #define SENDQUESTION -1 137527088Sminshall #define SENDESCAPE -3 137627088Sminshall 137727088Sminshall struct sendlist Sendlist[] = { 137827088Sminshall { "ao", AO, "Send Telnet Abort output" }, 137927088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 138027261Sminshall { "brk", BREAK, "Send Telnet Break" }, 138127088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 138227088Sminshall { "el", EL, "Send Telnet Erase Line" }, 138327261Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 138427088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 138527261Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 138627088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 138727261Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 138827088Sminshall { "?", SENDQUESTION, "Display send options" }, 138927088Sminshall { 0 } 139027088Sminshall }; 139127088Sminshall 139227261Sminshall struct sendlist Sendlist2[] = { /* some synonyms */ 139327261Sminshall { "break", BREAK, 0 }, 139427261Sminshall 139527261Sminshall { "intp", IP, 0 }, 139627261Sminshall { "interrupt", IP, 0 }, 139727261Sminshall { "intr", IP, 0 }, 139827261Sminshall 139927261Sminshall { "help", SENDQUESTION, 0 }, 140027261Sminshall 140127261Sminshall { 0 } 140227261Sminshall }; 140327261Sminshall 140427088Sminshall char ** 140527088Sminshall getnextsend(name) 140627088Sminshall char *name; 140727088Sminshall { 140827088Sminshall struct sendlist *c = (struct sendlist *) name; 140927088Sminshall 141027088Sminshall return (char **) (c+1); 141127088Sminshall } 141227088Sminshall 141327088Sminshall struct sendlist * 141427088Sminshall getsend(name) 141527088Sminshall char *name; 141627088Sminshall { 141727261Sminshall struct sendlist *sl; 141827261Sminshall 141927261Sminshall if (sl = (struct sendlist *) 142027261Sminshall genget(name, (char **) Sendlist, getnextsend)) { 142127261Sminshall return sl; 142227261Sminshall } else { 142327261Sminshall return (struct sendlist *) 142427261Sminshall genget(name, (char **) Sendlist2, getnextsend); 142527261Sminshall } 142627088Sminshall } 142727088Sminshall 142827088Sminshall sendcmd(argc, argv) 142927088Sminshall int argc; 143027088Sminshall char **argv; 143127088Sminshall { 143227088Sminshall int what; /* what we are sending this time */ 143327088Sminshall int count; /* how many bytes we are going to need to send */ 143427088Sminshall int hadsynch; /* are we going to process a "synch"? */ 143527088Sminshall int i; 143627261Sminshall int question = 0; /* was at least one argument a question */ 143727088Sminshall struct sendlist *s; /* pointer to current command */ 143827088Sminshall 143927088Sminshall if (argc < 2) { 144027088Sminshall printf("need at least one argument for 'send' command\n"); 144127088Sminshall printf("'send ?' for help\n"); 144227261Sminshall return 0; 144327088Sminshall } 144427088Sminshall /* 144527088Sminshall * First, validate all the send arguments. 144627088Sminshall * In addition, we see how much space we are going to need, and 144727088Sminshall * whether or not we will be doing a "SYNCH" operation (which 144827088Sminshall * flushes the network queue). 144927088Sminshall */ 145027088Sminshall count = 0; 145127088Sminshall hadsynch = 0; 145227088Sminshall for (i = 1; i < argc; i++) { 145327088Sminshall s = getsend(argv[i]); 145427088Sminshall if (s == 0) { 145527088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 145627088Sminshall argv[i]); 145727261Sminshall return 0; 145827186Sminshall } else if (s == Ambiguous(struct sendlist *)) { 145927088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 146027088Sminshall argv[i]); 146127261Sminshall return 0; 146227088Sminshall } 146327088Sminshall switch (s->what) { 146427088Sminshall case SENDQUESTION: 146527088Sminshall break; 146627088Sminshall case SENDESCAPE: 146727088Sminshall count += 1; 146827088Sminshall break; 146927088Sminshall case SYNCH: 147027088Sminshall hadsynch = 1; 147127088Sminshall count += 2; 147227088Sminshall break; 147327088Sminshall default: 147427088Sminshall count += 2; 147527088Sminshall break; 147627088Sminshall } 147727088Sminshall } 147827088Sminshall /* Now, do we have enough room? */ 147927228Sminshall if (NETROOM() < count) { 148027088Sminshall printf("There is not enough room in the buffer TO the network\n"); 148127088Sminshall printf("to process your request. Nothing will be done.\n"); 148227088Sminshall printf("('send synch' will throw away most data in the network\n"); 148327088Sminshall printf("buffer, if this might help.)\n"); 148427261Sminshall return 0; 148527088Sminshall } 148627088Sminshall /* OK, they are all OK, now go through again and actually send */ 148727088Sminshall for (i = 1; i < argc; i++) { 148827088Sminshall if (!(s = getsend(argv[i]))) { 148927088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 149027088Sminshall quit(); 149127088Sminshall /*NOTREACHED*/ 149227088Sminshall } 149327088Sminshall if (s->routine) { 149427088Sminshall (*s->routine)(s); 149527088Sminshall } else { 149627088Sminshall switch (what = s->what) { 149727261Sminshall case SYNCH: 149827261Sminshall dosynch(); 149927261Sminshall break; 150027088Sminshall case SENDQUESTION: 150127088Sminshall for (s = Sendlist; s->name; s++) { 150227261Sminshall if (s->help) { 150327088Sminshall printf(s->name); 150427088Sminshall if (s->help) { 150527088Sminshall printf("\t%s", s->help); 150627088Sminshall } 150727088Sminshall printf("\n"); 150827088Sminshall } 150927088Sminshall } 151027261Sminshall question = 1; 151127088Sminshall break; 151227088Sminshall case SENDESCAPE: 151327088Sminshall NETADD(escape); 151427088Sminshall break; 151527088Sminshall default: 151627088Sminshall NET2ADD(IAC, what); 151727088Sminshall break; 151827088Sminshall } 151927088Sminshall } 152027088Sminshall } 152127261Sminshall return !question; 152227088Sminshall } 152327088Sminshall 152427088Sminshall /* 152527088Sminshall * The following are the routines and data structures referred 152627088Sminshall * to by the arguments to the "toggle" command. 152727088Sminshall */ 152827088Sminshall 152927261Sminshall lclchars() 153027110Sminshall { 153127261Sminshall donelclchars = 1; 153227261Sminshall return 1; 153327110Sminshall } 153427110Sminshall 153527178Sminshall togdebug() 153627088Sminshall { 153727676Sminshall #ifndef NOT43 153827110Sminshall if (net > 0 && 153927186Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug)) 154027186Sminshall < 0) { 154127110Sminshall perror("setsockopt (SO_DEBUG)"); 154227186Sminshall } 154327676Sminshall #else NOT43 154427676Sminshall if (debug) { 154527676Sminshall if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 154627676Sminshall perror("setsockopt (SO_DEBUG)"); 154727676Sminshall } else 154827676Sminshall printf("Cannot turn off socket debugging\n"); 154927676Sminshall #endif NOT43 155027261Sminshall return 1; 155127088Sminshall } 155227088Sminshall 155327088Sminshall 155427088Sminshall 155527088Sminshall int togglehelp(); 155627088Sminshall 155727178Sminshall struct togglelist { 155827178Sminshall char *name; /* name of toggle */ 155927178Sminshall char *help; /* help message */ 156027186Sminshall int (*handler)(); /* routine to do actual setting */ 156127178Sminshall int dohelp; /* should we display help information */ 156227178Sminshall int *variable; 156327178Sminshall char *actionexplanation; 156427178Sminshall }; 156527178Sminshall 156627178Sminshall struct togglelist Togglelist[] = { 156727261Sminshall { "autoflush", 156827261Sminshall "toggle flushing of output when sending interrupt characters", 156927186Sminshall 0, 157027178Sminshall 1, 157127261Sminshall &autoflush, 157227261Sminshall "flush output when sending interrupt characters" }, 157327186Sminshall { "autosynch", 157427186Sminshall "toggle automatic sending of interrupt characters in urgent mode", 157527186Sminshall 0, 157627186Sminshall 1, 157727186Sminshall &autosynch, 157827186Sminshall "send interrupt characters in urgent mode" }, 157927178Sminshall { "crmod", 158027261Sminshall "toggle mapping of received carriage returns", 158127186Sminshall 0, 158227178Sminshall 1, 158327178Sminshall &crmod, 158427178Sminshall "map carriage return on output" }, 158527261Sminshall { "localchars", 158627261Sminshall "toggle local recognition of certain control characters", 158727261Sminshall lclchars, 158827261Sminshall 1, 158927261Sminshall &localchars, 159027261Sminshall "recognize certain control characters" }, 159127110Sminshall { " ", "", 0, 1 }, /* empty line */ 159227178Sminshall { "debug", 159327178Sminshall "(debugging) toggle debugging", 159427178Sminshall togdebug, 159527178Sminshall 1, 159627178Sminshall &debug, 159727178Sminshall "turn on socket level debugging" }, 159827261Sminshall { "netdata", 159927261Sminshall "(debugging) toggle printing of hexadecimal network data", 160027261Sminshall 0, 160127261Sminshall 1, 160227261Sminshall &netdata, 160327261Sminshall "print hexadecimal representation of network traffic" }, 160427178Sminshall { "options", 160527178Sminshall "(debugging) toggle viewing of options processing", 160627186Sminshall 0, 160727178Sminshall 1, 160827178Sminshall &showoptions, 160927178Sminshall "show option processing" }, 161027261Sminshall { " ", "", 0, 1 }, /* empty line */ 161127178Sminshall { "?", 161227178Sminshall "display help information", 161327178Sminshall togglehelp, 161427178Sminshall 1 }, 161527178Sminshall { "help", 161627178Sminshall "display help information", 161727178Sminshall togglehelp, 161827178Sminshall 0 }, 161927088Sminshall { 0 } 162027088Sminshall }; 162127088Sminshall 162227088Sminshall togglehelp() 162327088Sminshall { 162427178Sminshall struct togglelist *c; 162527088Sminshall 162627178Sminshall for (c = Togglelist; c->name; c++) { 162727088Sminshall if (c->dohelp) { 162827088Sminshall printf("%s\t%s\n", c->name, c->help); 162927088Sminshall } 163027088Sminshall } 163127261Sminshall return 0; 163227088Sminshall } 163327088Sminshall 163427088Sminshall char ** 163527088Sminshall getnexttoggle(name) 163627088Sminshall char *name; 163727088Sminshall { 163827178Sminshall struct togglelist *c = (struct togglelist *) name; 163927088Sminshall 164027088Sminshall return (char **) (c+1); 164127088Sminshall } 164227088Sminshall 164327178Sminshall struct togglelist * 164427088Sminshall gettoggle(name) 164527088Sminshall char *name; 164627088Sminshall { 164727178Sminshall return (struct togglelist *) 164827178Sminshall genget(name, (char **) Togglelist, getnexttoggle); 164927088Sminshall } 165027088Sminshall 165127088Sminshall toggle(argc, argv) 165227088Sminshall int argc; 165327088Sminshall char *argv[]; 165427088Sminshall { 165527261Sminshall int retval = 1; 165627088Sminshall char *name; 165727178Sminshall struct togglelist *c; 165827088Sminshall 165927088Sminshall if (argc < 2) { 166027088Sminshall fprintf(stderr, 166127088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 166227261Sminshall return 0; 166327088Sminshall } 166427088Sminshall argc--; 166527088Sminshall argv++; 166627088Sminshall while (argc--) { 166727088Sminshall name = *argv++; 166827088Sminshall c = gettoggle(name); 166927186Sminshall if (c == Ambiguous(struct togglelist *)) { 167027088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 167127088Sminshall name); 167227261Sminshall return 0; 167327088Sminshall } else if (c == 0) { 167427088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 167527088Sminshall name); 167627261Sminshall return 0; 167727088Sminshall } else { 167827186Sminshall if (c->variable) { 167927186Sminshall *c->variable = !*c->variable; /* invert it */ 168027186Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 168127186Sminshall c->actionexplanation); 168227186Sminshall } 168327186Sminshall if (c->handler) { 168427261Sminshall retval &= (*c->handler)(c); 168527186Sminshall } 168627088Sminshall } 168727088Sminshall } 168827261Sminshall return retval; 168927088Sminshall } 169027088Sminshall 169127088Sminshall /* 169227110Sminshall * The following perform the "set" command. 169327110Sminshall */ 169427110Sminshall 169527178Sminshall struct setlist { 169627178Sminshall char *name; /* name */ 169727110Sminshall char *help; /* help information */ 169827110Sminshall char *charp; /* where it is located at */ 169927110Sminshall }; 170027110Sminshall 170127178Sminshall struct setlist Setlist[] = { 170227110Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 170327110Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 170427261Sminshall { " ", "" }, 170527261Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 170627261Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 170727261Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 170827110Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 170927261Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 171027110Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 171127676Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc }, 171227110Sminshall { 0 } 171327110Sminshall }; 171427110Sminshall 171527110Sminshall char ** 171627178Sminshall getnextset(name) 171727110Sminshall char *name; 171827110Sminshall { 171927178Sminshall struct setlist *c = (struct setlist *)name; 172027110Sminshall 172127110Sminshall return (char **) (c+1); 172227110Sminshall } 172327110Sminshall 172427178Sminshall struct setlist * 172527178Sminshall getset(name) 172627110Sminshall char *name; 172727110Sminshall { 172827178Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 172927110Sminshall } 173027110Sminshall 173127110Sminshall setcmd(argc, argv) 173227110Sminshall int argc; 173327110Sminshall char *argv[]; 173427110Sminshall { 173527110Sminshall int value; 173627178Sminshall struct setlist *ct; 173727110Sminshall 173827110Sminshall /* XXX back we go... sigh */ 173927110Sminshall if (argc != 3) { 174027261Sminshall if ((argc == 2) && 174127261Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 174227261Sminshall for (ct = Setlist; ct->name; ct++) { 174327261Sminshall printf("%s\t%s\n", ct->name, ct->help); 174427261Sminshall } 174527261Sminshall printf("?\tdisplay help information\n"); 174627261Sminshall } else { 174727261Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 174827110Sminshall } 174927261Sminshall return 0; 175027110Sminshall } 175127110Sminshall 175227178Sminshall ct = getset(argv[1]); 175327110Sminshall if (ct == 0) { 175427110Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 175527110Sminshall argv[1]); 175627261Sminshall return 0; 175727186Sminshall } else if (ct == Ambiguous(struct setlist *)) { 175827110Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 175927110Sminshall argv[1]); 176027261Sminshall return 0; 176127110Sminshall } else { 176227110Sminshall if (strcmp("off", argv[2])) { 176327110Sminshall value = special(argv[2]); 176427110Sminshall } else { 176527110Sminshall value = -1; 176627110Sminshall } 176727110Sminshall *(ct->charp) = value; 176827178Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 176927110Sminshall } 177027261Sminshall return 1; 177127110Sminshall } 177227110Sminshall 177327110Sminshall /* 177427110Sminshall * The following are the data structures and routines for the 177527110Sminshall * 'mode' command. 177627110Sminshall */ 177727110Sminshall 177827110Sminshall dolinemode() 177927110Sminshall { 178027110Sminshall if (hisopts[TELOPT_SGA]) { 178127676Sminshall wontoption(TELOPT_SGA, 0); 178227110Sminshall } 178327110Sminshall if (hisopts[TELOPT_ECHO]) { 178427676Sminshall wontoption(TELOPT_ECHO, 0); 178527110Sminshall } 178627110Sminshall } 178727110Sminshall 178827110Sminshall docharmode() 178927110Sminshall { 179027110Sminshall if (!hisopts[TELOPT_SGA]) { 179127676Sminshall willoption(TELOPT_SGA, 0); 179227110Sminshall } 179327110Sminshall if (!hisopts[TELOPT_ECHO]) { 179427676Sminshall willoption(TELOPT_ECHO, 0); 179527110Sminshall } 179627110Sminshall } 179727110Sminshall 179827110Sminshall struct cmd Modelist[] = { 179927261Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 180027110Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 180127110Sminshall { 0 }, 180227110Sminshall }; 180327110Sminshall 180427110Sminshall char ** 180527110Sminshall getnextmode(name) 180627110Sminshall char *name; 180727110Sminshall { 180827110Sminshall struct cmd *c = (struct cmd *) name; 180927110Sminshall 181027110Sminshall return (char **) (c+1); 181127110Sminshall } 181227110Sminshall 181327110Sminshall struct cmd * 181427110Sminshall getmodecmd(name) 181527110Sminshall char *name; 181627110Sminshall { 181727110Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 181827110Sminshall } 181927110Sminshall 182027110Sminshall modecmd(argc, argv) 182127110Sminshall int argc; 182227110Sminshall char *argv[]; 182327110Sminshall { 182427110Sminshall struct cmd *mt; 182527110Sminshall 182627110Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 182727110Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 182827110Sminshall for (mt = Modelist; mt->name; mt++) { 182927110Sminshall printf("%s\t%s\n", mt->name, mt->help); 183027110Sminshall } 183127261Sminshall return 0; 183227110Sminshall } 183327110Sminshall mt = getmodecmd(argv[1]); 183427110Sminshall if (mt == 0) { 183527110Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 183627261Sminshall return 0; 183727186Sminshall } else if (mt == Ambiguous(struct cmd *)) { 183827110Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 183927261Sminshall return 0; 184027110Sminshall } else { 184127110Sminshall (*mt->handler)(); 184227110Sminshall } 184327261Sminshall return 1; 184427110Sminshall } 184527110Sminshall 184627110Sminshall /* 184727178Sminshall * The following data structures and routines implement the 184827178Sminshall * "display" command. 184927178Sminshall */ 185027178Sminshall 185127178Sminshall display(argc, argv) 185227178Sminshall int argc; 185327178Sminshall char *argv[]; 185427178Sminshall { 185527178Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 185627178Sminshall if (*tl->variable) { \ 185727178Sminshall printf("will"); \ 185827178Sminshall } else { \ 185927178Sminshall printf("won't"); \ 186027178Sminshall } \ 186127178Sminshall printf(" %s.\n", tl->actionexplanation); \ 186227178Sminshall } 186327178Sminshall 186427261Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 186527261Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 186627261Sminshall } 186727178Sminshall 186827178Sminshall struct togglelist *tl; 186927178Sminshall struct setlist *sl; 187027178Sminshall 187127178Sminshall if (argc == 1) { 187227178Sminshall for (tl = Togglelist; tl->name; tl++) { 187327178Sminshall dotog(tl); 187427178Sminshall } 187527261Sminshall printf("\n"); 187627178Sminshall for (sl = Setlist; sl->name; sl++) { 187727178Sminshall doset(sl); 187827178Sminshall } 187927178Sminshall } else { 188027178Sminshall int i; 188127178Sminshall 188227178Sminshall for (i = 1; i < argc; i++) { 188327178Sminshall sl = getset(argv[i]); 188427178Sminshall tl = gettoggle(argv[i]); 188527186Sminshall if ((sl == Ambiguous(struct setlist *)) || 188627186Sminshall (tl == Ambiguous(struct togglelist *))) { 188727178Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 188827261Sminshall return 0; 188927178Sminshall } else if (!sl && !tl) { 189027178Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 189127261Sminshall return 0; 189227178Sminshall } else { 189327186Sminshall if (tl) { 189427186Sminshall dotog(tl); 189527186Sminshall } 189627186Sminshall if (sl) { 189727186Sminshall doset(sl); 189827186Sminshall } 189927178Sminshall } 190027178Sminshall } 190127178Sminshall } 190227261Sminshall return 1; 190327178Sminshall #undef doset(sl) 190427178Sminshall #undef dotog(tl) 190527178Sminshall } 190627178Sminshall 190727178Sminshall /* 190827088Sminshall * The following are the data structures, and many of the routines, 190927088Sminshall * relating to command processing. 191027088Sminshall */ 191127088Sminshall 191227088Sminshall /* 191327088Sminshall * Set the escape character. 191427088Sminshall */ 191527088Sminshall setescape(argc, argv) 191627088Sminshall int argc; 191727088Sminshall char *argv[]; 191827088Sminshall { 191927088Sminshall register char *arg; 192027088Sminshall char buf[50]; 192127088Sminshall 192227186Sminshall printf( 192327186Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 192427186Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 192527088Sminshall if (argc > 2) 192627088Sminshall arg = argv[1]; 192727088Sminshall else { 192827088Sminshall printf("new escape character: "); 192927088Sminshall gets(buf); 193027088Sminshall arg = buf; 193127088Sminshall } 193227088Sminshall if (arg[0] != '\0') 193327088Sminshall escape = arg[0]; 193427088Sminshall printf("Escape character is '%s'.\n", control(escape)); 193527088Sminshall fflush(stdout); 193627261Sminshall return 1; 193727088Sminshall } 193827088Sminshall 193927088Sminshall /*VARARGS*/ 194027261Sminshall togcrmod() 194127261Sminshall { 194227261Sminshall crmod = !crmod; 194327261Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 194427261Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 194527261Sminshall fflush(stdout); 194627261Sminshall return 1; 194727261Sminshall } 194827261Sminshall 194927261Sminshall /*VARARGS*/ 195027088Sminshall suspend() 195127088Sminshall { 195227110Sminshall setcommandmode(); 195327088Sminshall kill(0, SIGTSTP); 195427088Sminshall /* reget parameters in case they were changed */ 195527088Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 195627088Sminshall ioctl(0, TIOCGETC, (char *)&otc); 195727088Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 195827261Sminshall return 1; 195927088Sminshall } 196027088Sminshall 196127088Sminshall /*VARARGS*/ 196227088Sminshall bye() 196327088Sminshall { 196427088Sminshall register char *op; 196527088Sminshall 196627088Sminshall if (connected) { 196727088Sminshall shutdown(net, 2); 196827088Sminshall printf("Connection closed.\n"); 196927088Sminshall close(net); 197027088Sminshall connected = 0; 197127088Sminshall /* reset his options */ 197227088Sminshall for (op = hisopts; op < &hisopts[256]; op++) 197327088Sminshall *op = 0; 197427088Sminshall } 197527261Sminshall return 1; 197627088Sminshall } 197727088Sminshall 197827088Sminshall /*VARARGS*/ 197927088Sminshall quit() 198027088Sminshall { 198127261Sminshall (void) call(bye, "bye", 0); 198227088Sminshall exit(0); 198327261Sminshall /*NOTREACHED*/ 198427088Sminshall } 198527088Sminshall 198627088Sminshall /* 198727088Sminshall * Print status about the connection. 198827088Sminshall */ 198927186Sminshall /*ARGSUSED*/ 199027178Sminshall status(argc, argv) 199127178Sminshall int argc; 199227178Sminshall char *argv[]; 199327088Sminshall { 199427178Sminshall if (connected) { 199527178Sminshall printf("Connected to %s.\n", hostname); 199627178Sminshall if (argc < 2) { 199727178Sminshall printf("Operating in %s.\n", modedescriptions[getconnmode()]); 199827261Sminshall if (localchars) { 199927178Sminshall printf("Catching signals locally.\n"); 200027178Sminshall } 200127110Sminshall } 200227178Sminshall } else { 200327178Sminshall printf("No connection.\n"); 200427178Sminshall } 200527178Sminshall printf("Escape character is '%s'.\n", control(escape)); 200627178Sminshall fflush(stdout); 200727261Sminshall return 1; 200827088Sminshall } 200927088Sminshall 201027088Sminshall tn(argc, argv) 201127088Sminshall int argc; 201227088Sminshall char *argv[]; 201327088Sminshall { 201427088Sminshall register struct hostent *host = 0; 201527088Sminshall 201627088Sminshall if (connected) { 201727088Sminshall printf("?Already connected to %s\n", hostname); 201827261Sminshall return 0; 201927088Sminshall } 202027088Sminshall if (argc < 2) { 202127186Sminshall (void) strcpy(line, "Connect "); 202227088Sminshall printf("(to) "); 202327088Sminshall gets(&line[strlen(line)]); 202427088Sminshall makeargv(); 202527088Sminshall argc = margc; 202627088Sminshall argv = margv; 202727088Sminshall } 202827088Sminshall if (argc > 3) { 202927088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 203027261Sminshall return 0; 203127088Sminshall } 203227088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 203327088Sminshall if (sin.sin_addr.s_addr != -1) { 203427088Sminshall sin.sin_family = AF_INET; 203527186Sminshall (void) strcpy(hnamebuf, argv[1]); 203627088Sminshall hostname = hnamebuf; 203727088Sminshall } else { 203827088Sminshall host = gethostbyname(argv[1]); 203927088Sminshall if (host) { 204027088Sminshall sin.sin_family = host->h_addrtype; 204127676Sminshall #ifndef NOT43 204227088Sminshall bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 204327088Sminshall host->h_length); 204427676Sminshall #else NOT43 204527676Sminshall bcopy(host->h_addr, (caddr_t)&sin.sin_addr, 204627676Sminshall host->h_length); 204727676Sminshall #endif NOT43 204827088Sminshall hostname = host->h_name; 204927088Sminshall } else { 205027088Sminshall printf("%s: unknown host\n", argv[1]); 205127261Sminshall return 0; 205227088Sminshall } 205327088Sminshall } 205427088Sminshall sin.sin_port = sp->s_port; 205527088Sminshall if (argc == 3) { 205627088Sminshall sin.sin_port = atoi(argv[2]); 205727186Sminshall if (sin.sin_port == 0) { 205827088Sminshall sp = getservbyname(argv[2], "tcp"); 205927088Sminshall if (sp) 206027088Sminshall sin.sin_port = sp->s_port; 206127088Sminshall else { 206227088Sminshall printf("%s: bad port number\n", argv[2]); 206327261Sminshall return 0; 206427088Sminshall } 206527088Sminshall } else { 206627088Sminshall sin.sin_port = atoi(argv[2]); 206727088Sminshall sin.sin_port = htons(sin.sin_port); 206827088Sminshall } 206927088Sminshall telnetport = 0; 207027110Sminshall } else { 207127110Sminshall telnetport = 1; 207227088Sminshall } 207327088Sminshall signal(SIGINT, intr); 207427110Sminshall signal(SIGQUIT, intr2); 207527088Sminshall signal(SIGPIPE, deadpeer); 207627088Sminshall printf("Trying...\n"); 207727088Sminshall do { 207827088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 207927088Sminshall if (net < 0) { 208027088Sminshall perror("telnet: socket"); 208127261Sminshall return 0; 208227088Sminshall } 208327676Sminshall #ifndef NOT43 208427186Sminshall if (debug && 208527186Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, 208627676Sminshall (char *)&debug, sizeof(debug)) < 0) 208727676Sminshall #else NOT43 208827676Sminshall if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 208927676Sminshall #endif NOT43 209027088Sminshall perror("setsockopt (SO_DEBUG)"); 209127676Sminshall 209227186Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 209327676Sminshall #ifndef NOT43 209427088Sminshall if (host && host->h_addr_list[1]) { 209527088Sminshall int oerrno = errno; 209627088Sminshall 209727088Sminshall fprintf(stderr, 209827088Sminshall "telnet: connect to address %s: ", 209927088Sminshall inet_ntoa(sin.sin_addr)); 210027088Sminshall errno = oerrno; 210127186Sminshall perror((char *)0); 210227088Sminshall host->h_addr_list++; 210327088Sminshall bcopy(host->h_addr_list[0], 210427088Sminshall (caddr_t)&sin.sin_addr, host->h_length); 210527088Sminshall fprintf(stderr, "Trying %s...\n", 210627088Sminshall inet_ntoa(sin.sin_addr)); 210727088Sminshall (void) close(net); 210827088Sminshall continue; 210927088Sminshall } 211027676Sminshall #endif NOT43 211127088Sminshall perror("telnet: connect"); 211227088Sminshall signal(SIGINT, SIG_DFL); 211327261Sminshall signal(SIGQUIT, SIG_DFL); 211427261Sminshall return 0; 211527088Sminshall } 211627088Sminshall connected++; 211727088Sminshall } while (connected == 0); 211827178Sminshall call(status, "status", "notmuch", 0); 211927088Sminshall if (setjmp(peerdied) == 0) 212027088Sminshall telnet(); 212127088Sminshall fprintf(stderr, "Connection closed by foreign host.\n"); 212227088Sminshall exit(1); 212327261Sminshall /*NOTREACHED*/ 212427088Sminshall } 212527088Sminshall 212627088Sminshall 212727088Sminshall #define HELPINDENT (sizeof ("connect")) 212827088Sminshall 212927088Sminshall char openhelp[] = "connect to a site"; 213027088Sminshall char closehelp[] = "close current connection"; 213127088Sminshall char quithelp[] = "exit telnet"; 213227088Sminshall char zhelp[] = "suspend telnet"; 213327088Sminshall char statushelp[] = "print status information"; 213427088Sminshall char helphelp[] = "print help information"; 213527110Sminshall char sendhelp[] = "transmit special characters ('send ?' for more)"; 213627178Sminshall char sethelp[] = "set operating parameters ('set ?' for more)"; 213727178Sminshall char togglestring[] ="toggle operating parameters ('toggle ?' for more)"; 213827178Sminshall char displayhelp[] = "display operating parameters"; 213927178Sminshall char modehelp[] = 214027178Sminshall "try to enter line-by-line or character-at-a-time mode"; 214127088Sminshall 214227088Sminshall int help(); 214327088Sminshall 214427088Sminshall struct cmd cmdtab[] = { 214527261Sminshall { "close", closehelp, bye, 1, 1 }, 214627261Sminshall { "display", displayhelp, display, 1, 0 }, 214727261Sminshall { "mode", modehelp, modecmd, 1, 1 }, 214827110Sminshall { "open", openhelp, tn, 1, 0 }, 214927110Sminshall { "quit", quithelp, quit, 1, 0 }, 215027110Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 215127178Sminshall { "set", sethelp, setcmd, 1, 0 }, 215227261Sminshall { "status", statushelp, status, 1, 0 }, 215327110Sminshall { "toggle", togglestring, toggle, 1, 0 }, 215427261Sminshall { "z", zhelp, suspend, 1, 0 }, 215527110Sminshall { "?", helphelp, help, 1, 0 }, 215627261Sminshall 0 215727261Sminshall }; 215827261Sminshall 215927261Sminshall char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 216027261Sminshall char escapehelp[] = "deprecated command -- use 'set escape' instead"; 216127261Sminshall 216227261Sminshall struct cmd cmdtab2[] = { 216327110Sminshall { "help", helphelp, help, 0, 0 }, 216427261Sminshall { "escape", escapehelp, setescape, 1, 0 }, 216527261Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 216627088Sminshall 0 216727088Sminshall }; 216827088Sminshall 216927088Sminshall /* 217027088Sminshall * Help command. 217127088Sminshall */ 217227088Sminshall help(argc, argv) 217327088Sminshall int argc; 217427088Sminshall char *argv[]; 217527088Sminshall { 217627088Sminshall register struct cmd *c; 217727088Sminshall 217827088Sminshall if (argc == 1) { 217927088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 218027088Sminshall for (c = cmdtab; c->name; c++) 218127088Sminshall if (c->dohelp) { 218227088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 218327088Sminshall c->help); 218427088Sminshall } 218527261Sminshall return 0; 218627088Sminshall } 218727088Sminshall while (--argc > 0) { 218827088Sminshall register char *arg; 218927088Sminshall arg = *++argv; 219027088Sminshall c = getcmd(arg); 219127186Sminshall if (c == Ambiguous(struct cmd *)) 219227088Sminshall printf("?Ambiguous help command %s\n", arg); 219327088Sminshall else if (c == (struct cmd *)0) 219427088Sminshall printf("?Invalid help command %s\n", arg); 219527088Sminshall else 219627088Sminshall printf("%s\n", c->help); 219727088Sminshall } 219827261Sminshall return 0; 219927088Sminshall } 220027088Sminshall /* 220127088Sminshall * Call routine with argc, argv set from args (terminated by 0). 220227088Sminshall * VARARGS2 220327088Sminshall */ 220427088Sminshall call(routine, args) 220527088Sminshall int (*routine)(); 220627186Sminshall char *args; 220727088Sminshall { 220827186Sminshall register char **argp; 220927088Sminshall register int argc; 221027088Sminshall 221127088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 221227088Sminshall ; 221327261Sminshall return (*routine)(argc, &args); 221427088Sminshall } 221527088Sminshall 221627088Sminshall makeargv() 221727088Sminshall { 221827088Sminshall register char *cp; 221927088Sminshall register char **argp = margv; 222027088Sminshall 222127088Sminshall margc = 0; 222227088Sminshall for (cp = line; *cp;) { 222327088Sminshall while (isspace(*cp)) 222427088Sminshall cp++; 222527088Sminshall if (*cp == '\0') 222627088Sminshall break; 222727088Sminshall *argp++ = cp; 222827088Sminshall margc += 1; 222927088Sminshall while (*cp != '\0' && !isspace(*cp)) 223027088Sminshall cp++; 223127088Sminshall if (*cp == '\0') 223227088Sminshall break; 223327088Sminshall *cp++ = '\0'; 223427088Sminshall } 223527088Sminshall *argp++ = 0; 223627088Sminshall } 223727088Sminshall 223827088Sminshall char ** 223927088Sminshall getnextcmd(name) 224027088Sminshall char *name; 224127088Sminshall { 224227088Sminshall struct cmd *c = (struct cmd *) name; 224327088Sminshall 224427088Sminshall return (char **) (c+1); 224527088Sminshall } 224627088Sminshall 224727088Sminshall struct cmd * 224827088Sminshall getcmd(name) 224927088Sminshall char *name; 225027088Sminshall { 225127261Sminshall struct cmd *cm; 225227261Sminshall 225327261Sminshall if (cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) { 225427261Sminshall return cm; 225527261Sminshall } else { 225627261Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 225727261Sminshall } 225827088Sminshall } 225927088Sminshall 226027088Sminshall command(top) 226127088Sminshall int top; 226227088Sminshall { 226327088Sminshall register struct cmd *c; 226427088Sminshall 226527110Sminshall setcommandmode(); 226627261Sminshall if (!top) { 226727088Sminshall putchar('\n'); 226827261Sminshall } else { 226927088Sminshall signal(SIGINT, SIG_DFL); 227027261Sminshall signal(SIGQUIT, SIG_DFL); 227127261Sminshall } 227227088Sminshall for (;;) { 227327088Sminshall printf("%s> ", prompt); 227427088Sminshall if (gets(line) == 0) { 227527088Sminshall if (feof(stdin)) 227627088Sminshall quit(); 227727088Sminshall break; 227827088Sminshall } 227927088Sminshall if (line[0] == 0) 228027088Sminshall break; 228127088Sminshall makeargv(); 228227088Sminshall c = getcmd(margv[0]); 228327186Sminshall if (c == Ambiguous(struct cmd *)) { 228427088Sminshall printf("?Ambiguous command\n"); 228527088Sminshall continue; 228627088Sminshall } 228727088Sminshall if (c == 0) { 228827088Sminshall printf("?Invalid command\n"); 228927088Sminshall continue; 229027088Sminshall } 229127088Sminshall if (c->needconnect && !connected) { 229227088Sminshall printf("?Need to be connected first.\n"); 229327088Sminshall continue; 229427088Sminshall } 229527261Sminshall if ((*c->handler)(margc, margv)) { 229627088Sminshall break; 229727261Sminshall } 229827088Sminshall } 229927088Sminshall if (!top) { 230027110Sminshall if (!connected) { 230127088Sminshall longjmp(toplevel, 1); 230227110Sminshall /*NOTREACHED*/ 230327110Sminshall } 230427110Sminshall setconnmode(); 230527088Sminshall } 230627088Sminshall } 230727186Sminshall 230827186Sminshall /* 230927186Sminshall * main. Parse arguments, invoke the protocol or command parser. 231027186Sminshall */ 231127186Sminshall 231227186Sminshall 231327186Sminshall main(argc, argv) 231427186Sminshall int argc; 231527186Sminshall char *argv[]; 231627186Sminshall { 231727186Sminshall sp = getservbyname("telnet", "tcp"); 231827186Sminshall if (sp == 0) { 231927186Sminshall fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 232027186Sminshall exit(1); 232127186Sminshall } 232227186Sminshall NetTrace = stdout; 232327186Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 232427186Sminshall ioctl(0, TIOCGETC, (char *)&otc); 232527186Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 232627228Sminshall #if defined(LNOFLSH) 232727228Sminshall ioctl(0, TIOCLGET, (char *)&autoflush); 232827261Sminshall autoflush = !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ 232927261Sminshall #else /* LNOFLSH */ 233027261Sminshall autoflush = 1; 233127228Sminshall #endif /* LNOFLSH */ 233227186Sminshall ntc = otc; 233327228Sminshall nltc = oltc; 233427186Sminshall nttyb = ottyb; 233527186Sminshall setbuf(stdin, (char *)0); 233627186Sminshall setbuf(stdout, (char *)0); 233727186Sminshall prompt = argv[0]; 233827186Sminshall if (argc > 1 && !strcmp(argv[1], "-d")) { 233927186Sminshall debug = 1; 234027186Sminshall argv++; 234127186Sminshall argc--; 234227186Sminshall } 234327186Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 234427186Sminshall argv++; 234527186Sminshall argc--; 234627186Sminshall if (argc > 1) { /* get file name */ 234727186Sminshall NetTrace = fopen(argv[1], "w"); 234827186Sminshall argv++; 234927186Sminshall argc--; 235027186Sminshall if (NetTrace == NULL) { 235127186Sminshall NetTrace = stdout; 235227186Sminshall } 235327186Sminshall } 235427186Sminshall } 235527186Sminshall if (argc != 1) { 235627186Sminshall if (setjmp(toplevel) != 0) 235727186Sminshall exit(0); 235827186Sminshall tn(argc, argv); 235927186Sminshall } 236027186Sminshall setjmp(toplevel); 236127186Sminshall for (;;) 236227186Sminshall command(1); 236327186Sminshall } 2364