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*27676Sminshall static char sccsid[] = "@(#)telnet.c 5.12 (Berkeley) 4/22/86"; 1521580Sdist #endif not lint 1621580Sdist 176000Sroot /* 186000Sroot * User telnet program. 196000Sroot */ 209217Ssam #include <sys/types.h> 219217Ssam #include <sys/socket.h> 229972Ssam #include <sys/ioctl.h> 2327178Sminshall #include <sys/time.h> 249217Ssam 259217Ssam #include <netinet/in.h> 269217Ssam 2712212Ssam #define TELOPTS 2812212Ssam #include <arpa/telnet.h> 2927186Sminshall #include <arpa/inet.h> 3012212Ssam 316000Sroot #include <stdio.h> 326000Sroot #include <ctype.h> 336000Sroot #include <errno.h> 346000Sroot #include <signal.h> 356000Sroot #include <setjmp.h> 368345Ssam #include <netdb.h> 3727186Sminshall #include <strings.h> 389217Ssam 3927178Sminshall 4027178Sminshall 41*27676Sminshall #ifndef FD_SETSIZE 4227178Sminshall /* 4327178Sminshall * The following is defined just in case someone should want to run 4427178Sminshall * this telnet on a 4.2 system. 4527178Sminshall * 4627178Sminshall */ 4727178Sminshall 48*27676Sminshall #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n))) 49*27676Sminshall #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n))) 50*27676Sminshall #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n))) 51*27676Sminshall #define FD_ZERO(p) ((p)->fds_bits[0] = 0) 5227178Sminshall 5327178Sminshall #endif 5427178Sminshall 5527228Sminshall #define strip(x) ((x)&0x7f) 566000Sroot 5727228Sminshall char ttyobuf[2*BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; 5827228Sminshall #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } } 5927228Sminshall #define TTYLOC() (tfrontp) 6027228Sminshall #define TTYMAX() (ttyobuf+sizeof ttyobuf-1) 6127228Sminshall #define TTYMIN() (netobuf) 6227228Sminshall #define TTYBYTES() (tfrontp-tbackp) 6327228Sminshall #define TTYROOM() (TTYMAX()-TTYLOC()+1) 6427088Sminshall 6527228Sminshall char netobuf[2*BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 6627088Sminshall #define NETADD(c) { *nfrontp++ = c; } 6727088Sminshall #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } 6827088Sminshall #define NETLOC() (nfrontp) 6927228Sminshall #define NETMAX() (netobuf+sizeof netobuf-1) 7027228Sminshall #define NETBYTES() (nfrontp-nbackp) 7127228Sminshall #define NETROOM() (NETMAX()-NETLOC()+1) 7227088Sminshall char *neturg = 0; /* one past last byte of urgent data */ 736000Sroot 74*27676Sminshall char subbuffer[100], *subpointer, *subend; /* buffer for sub-options */ 75*27676Sminshall #define SB_CLEAR() subpointer = subbuffer; 76*27676Sminshall #define SB_TERM() subend = subpointer; 77*27676Sminshall #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 78*27676Sminshall *subpointer++ = (c); \ 79*27676Sminshall } 80*27676Sminshall 816000Sroot char hisopts[256]; 826000Sroot char myopts[256]; 836000Sroot 846000Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 856000Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 866000Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 876000Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 886000Sroot 8927088Sminshall struct cmd { 9027088Sminshall char *name; /* command name */ 9127088Sminshall char *help; /* help string */ 9227088Sminshall int (*handler)(); /* routine which executes command */ 9327088Sminshall int dohelp; /* Should we give general help information? */ 9427088Sminshall int needconnect; /* Do we need to be connected to execute? */ 9527088Sminshall }; 9627088Sminshall 976000Sroot int connected; 986000Sroot int net; 9927088Sminshall int tout; 1009972Ssam int showoptions = 0; 10110339Ssam int debug = 0; 1029972Ssam int crmod = 0; 10327088Sminshall int netdata = 0; 10427021Sminshall static FILE *NetTrace; 10525289Skarels int telnetport = 1; 10627088Sminshall 10727088Sminshall 1086000Sroot char *prompt; 1099972Ssam char escape = CTRL(]); 11027110Sminshall char echoc = CTRL(E); 1116000Sroot 11227186Sminshall int SYNCHing = 0; /* we are in TELNET SYNCH mode */ 11327186Sminshall int flushout = 0; /* flush output */ 11427228Sminshall int autoflush = 0; /* flush output when interrupting? */ 11527186Sminshall int autosynch = 0; /* send interrupt characters with SYNCH? */ 11627261Sminshall int localchars = 0; /* we recognize interrupt/quit */ 11727261Sminshall int donelclchars = 0; /* the user has set "localchars" */ 11827186Sminshall int dontlecho = 0; /* do we suppress local echoing right now? */ 11927186Sminshall 1206000Sroot char line[200]; 1216000Sroot int margc; 1226000Sroot char *margv[20]; 1236000Sroot 1246000Sroot jmp_buf toplevel; 1256000Sroot jmp_buf peerdied; 1266000Sroot 1276000Sroot extern int errno; 1286000Sroot 1296000Sroot 1309972Ssam struct sockaddr_in sin; 1316000Sroot 1326000Sroot struct cmd *getcmd(); 1338345Ssam struct servent *sp; 1346000Sroot 13527110Sminshall struct tchars otc, ntc; 13627228Sminshall struct ltchars oltc, nltc; 13727110Sminshall struct sgttyb ottyb, nttyb; 13827110Sminshall int globalmode = 0; 13927110Sminshall int flushline = 1; 1408378Ssam 14127110Sminshall char *hostname; 14227110Sminshall char hnamebuf[32]; 14327110Sminshall 14427110Sminshall /* 14527110Sminshall * The following are some clocks used to decide how to interpret 14627178Sminshall * the relationship between various variables. 14727110Sminshall */ 14827110Sminshall 14927110Sminshall struct { 15027110Sminshall int 15127110Sminshall system, /* what the current time is */ 15227110Sminshall echotoggle, /* last time user entered echo character */ 15327178Sminshall modenegotiated, /* last time operating mode negotiated */ 15427178Sminshall didnetreceive, /* last time we read data from network */ 15527178Sminshall gotDM; /* when did we last see a data mark */ 15627186Sminshall } clocks; 15727110Sminshall 15827186Sminshall #define settimer(x) clocks.x = clocks.system++ 15927110Sminshall 16027110Sminshall /* 16127110Sminshall * Various utility routines. 16227110Sminshall */ 1636000Sroot 16427186Sminshall char *ambiguous; /* special return value */ 16527186Sminshall #define Ambiguous(t) ((t)&ambiguous) 16627186Sminshall 16727186Sminshall 16827088Sminshall char ** 16927088Sminshall genget(name, table, next) 17027088Sminshall char *name; /* name to match */ 17127088Sminshall char **table; /* name entry in table */ 17227088Sminshall char **(*next)(); /* routine to return next entry in table */ 1736000Sroot { 17427088Sminshall register char *p, *q; 17527088Sminshall register char **c, **found; 17627088Sminshall register int nmatches, longest; 1776000Sroot 17827088Sminshall longest = 0; 17927088Sminshall nmatches = 0; 18027088Sminshall found = 0; 18127088Sminshall for (c = table; p = *c; c = (*next)(c)) { 18227088Sminshall for (q = name; *q == *p++; q++) 18327088Sminshall if (*q == 0) /* exact match? */ 18427088Sminshall return (c); 18527088Sminshall if (!*q) { /* the name was a prefix */ 18627088Sminshall if (q - name > longest) { 18727088Sminshall longest = q - name; 18827088Sminshall nmatches = 1; 18927088Sminshall found = c; 19027088Sminshall } else if (q - name == longest) 19127088Sminshall nmatches++; 1928377Ssam } 1936000Sroot } 19427088Sminshall if (nmatches > 1) 19527186Sminshall return Ambiguous(char **); 19627088Sminshall return (found); 1976000Sroot } 1986000Sroot 19927110Sminshall /* 20027110Sminshall * Make a character string into a number. 20127110Sminshall * 20227186Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 20327110Sminshall */ 2046000Sroot 20527110Sminshall special(s) 20627110Sminshall register char *s; 20727110Sminshall { 20827110Sminshall register char c; 20927110Sminshall char b; 21027110Sminshall 21127110Sminshall switch (*s) { 21227110Sminshall case '^': 21327110Sminshall b = *++s; 21427110Sminshall if (b == '?') { 21527228Sminshall c = b | 0x40; /* DEL */ 21627110Sminshall } else { 21727110Sminshall c = b & 0x1f; 21827110Sminshall } 21927110Sminshall break; 22027110Sminshall default: 22127110Sminshall c = *s; 22227110Sminshall break; 22327110Sminshall } 22427110Sminshall return c; 22527110Sminshall } 22627186Sminshall 22727186Sminshall /* 22827186Sminshall * Construct a control character sequence 22927186Sminshall * for a special character. 23027186Sminshall */ 23127186Sminshall char * 23227186Sminshall control(c) 23327186Sminshall register int c; 23427186Sminshall { 23527186Sminshall static char buf[3]; 23627186Sminshall 23727228Sminshall if (c == 0x7f) 23827186Sminshall return ("^?"); 23927186Sminshall if (c == '\377') { 24027186Sminshall return "off"; 24127186Sminshall } 24227186Sminshall if (c >= 0x20) { 24327186Sminshall buf[0] = c; 24427186Sminshall buf[1] = 0; 24527186Sminshall } else { 24627186Sminshall buf[0] = '^'; 24727186Sminshall buf[1] = '@'+c; 24827186Sminshall buf[2] = 0; 24927186Sminshall } 25027186Sminshall return (buf); 25127186Sminshall } 252*27676Sminshall 253*27676Sminshall 254*27676Sminshall /* 255*27676Sminshall * upcase() 256*27676Sminshall * 257*27676Sminshall * Upcase (in place) the argument. 258*27676Sminshall */ 259*27676Sminshall 260*27676Sminshall void 261*27676Sminshall upcase(argument) 262*27676Sminshall register char *argument; 263*27676Sminshall { 264*27676Sminshall register int c; 265*27676Sminshall 266*27676Sminshall while (c = *argument) { 267*27676Sminshall if (islower(c)) { 268*27676Sminshall *argument = toupper(c); 269*27676Sminshall } 270*27676Sminshall argument++; 271*27676Sminshall } 272*27676Sminshall } 27327110Sminshall 27427110Sminshall /* 27527186Sminshall * Check to see if any out-of-band data exists on a socket (for 27627186Sminshall * Telnet "synch" processing). 27727186Sminshall */ 27827186Sminshall 27927186Sminshall int 28027186Sminshall stilloob(s) 28127186Sminshall int s; /* socket number */ 28227186Sminshall { 28327186Sminshall static struct timeval timeout = { 0 }; 28427186Sminshall fd_set excepts; 28527186Sminshall int value; 28627186Sminshall 28727186Sminshall do { 28827186Sminshall FD_ZERO(&excepts); 28927186Sminshall FD_SET(s, &excepts); 29027186Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 29127186Sminshall } while ((value == -1) && (errno = EINTR)); 29227186Sminshall 29327186Sminshall if (value < 0) { 29427186Sminshall perror("select"); 29527186Sminshall quit(); 29627186Sminshall } 29727186Sminshall if (FD_ISSET(s, &excepts)) { 29827186Sminshall return 1; 29927186Sminshall } else { 30027186Sminshall return 0; 30127186Sminshall } 30227186Sminshall } 30327186Sminshall 30427186Sminshall 30527186Sminshall /* 30627186Sminshall * netflush 30727186Sminshall * Send as much data as possible to the network, 30827186Sminshall * handling requests for urgent data. 30927186Sminshall */ 31027186Sminshall 31127186Sminshall 31227186Sminshall netflush(fd) 31327186Sminshall { 31427186Sminshall int n; 31527186Sminshall 31627186Sminshall if ((n = nfrontp - nbackp) > 0) { 31727186Sminshall if (!neturg) { 31827186Sminshall n = write(fd, nbackp, n); /* normal write */ 31927186Sminshall } else { 32027186Sminshall n = neturg - nbackp; 32127186Sminshall /* 32227186Sminshall * In 4.2 (and 4.3) systems, there is some question about 32327186Sminshall * what byte in a sendOOB operation is the "OOB" data. 32427186Sminshall * To make ourselves compatible, we only send ONE byte 32527186Sminshall * out of band, the one WE THINK should be OOB (though 32627186Sminshall * we really have more the TCP philosophy of urgent data 32727186Sminshall * rather than the Unix philosophy of OOB data). 32827186Sminshall */ 32927186Sminshall if (n > 1) { 33027186Sminshall n = send(fd, nbackp, n-1, 0); /* send URGENT all by itself */ 33127186Sminshall } else { 33227186Sminshall n = send(fd, nbackp, n, MSG_OOB); /* URGENT data */ 33327186Sminshall } 33427186Sminshall } 33527186Sminshall } 33627186Sminshall if (n < 0) { 33727186Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 33827186Sminshall setcommandmode(); 33927186Sminshall perror(hostname); 34027186Sminshall close(fd); 34127186Sminshall neturg = 0; 34227186Sminshall longjmp(peerdied, -1); 34327186Sminshall /*NOTREACHED*/ 34427186Sminshall } 34527186Sminshall n = 0; 34627186Sminshall } 34727186Sminshall if (netdata && n) { 34827186Sminshall Dump('>', nbackp, n); 34927186Sminshall } 35027186Sminshall nbackp += n; 35127186Sminshall if (nbackp >= neturg) { 35227186Sminshall neturg = 0; 35327186Sminshall } 35427186Sminshall if (nbackp == nfrontp) { 35527186Sminshall nbackp = nfrontp = netobuf; 35627186Sminshall } 35727186Sminshall } 35827261Sminshall 35927261Sminshall /* 36027261Sminshall * nextitem() 36127261Sminshall * 36227261Sminshall * Return the address of the next "item" in the TELNET data 36327261Sminshall * stream. This will be the address of the next character if 36427261Sminshall * the current address is a user data character, or it will 36527261Sminshall * be the address of the character following the TELNET command 36627261Sminshall * if the current address is a TELNET IAC ("I Am a Command") 36727261Sminshall * character. 36827261Sminshall */ 36927186Sminshall 37027261Sminshall char * 37127261Sminshall nextitem(current) 37227261Sminshall char *current; 37327261Sminshall { 37427261Sminshall if ((*current&0xff) != IAC) { 37527261Sminshall return current+1; 37627261Sminshall } 37727261Sminshall switch (*(current+1)&0xff) { 37827261Sminshall case DO: 37927261Sminshall case DONT: 38027261Sminshall case WILL: 38127261Sminshall case WONT: 38227261Sminshall return current+3; 38327261Sminshall case SB: /* loop forever looking for the SE */ 38427261Sminshall { 38527261Sminshall register char *look = current+2; 38627261Sminshall 38727261Sminshall for (;;) { 38827261Sminshall if ((*look++&0xff) == IAC) { 38927261Sminshall if ((*look++&0xff) == SE) { 39027261Sminshall return look; 39127261Sminshall } 39227261Sminshall } 39327261Sminshall } 39427261Sminshall } 39527261Sminshall default: 39627261Sminshall return current+2; 39727261Sminshall } 39827261Sminshall } 39927186Sminshall /* 40027261Sminshall * netclear() 40127261Sminshall * 40227261Sminshall * We are about to do a TELNET SYNCH operation. Clear 40327261Sminshall * the path to the network. 40427261Sminshall * 40527261Sminshall * Things are a bit tricky since we may have sent the first 40627261Sminshall * byte or so of a previous TELNET command into the network. 40727261Sminshall * So, we have to scan the network buffer from the beginning 40827261Sminshall * until we are up to where we want to be. 40927261Sminshall * 41027261Sminshall * A side effect of what we do, just to keep things 41127261Sminshall * simple, is to clear the urgent data pointer. The principal 41227261Sminshall * caller should be setting the urgent data pointer AFTER calling 41327261Sminshall * us in any case. 41427261Sminshall */ 41527261Sminshall 41627261Sminshall netclear() 41727261Sminshall { 41827261Sminshall register char *thisitem, *next; 41927261Sminshall char *good; 42027261Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 42127261Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 42227261Sminshall 42327261Sminshall thisitem = netobuf; 42427261Sminshall 42527261Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 42627261Sminshall thisitem = next; 42727261Sminshall } 42827261Sminshall 42927261Sminshall /* Now, thisitem is first before/at boundary. */ 43027261Sminshall 43127261Sminshall good = netobuf; /* where the good bytes go */ 43227261Sminshall 43327261Sminshall while (nfrontp > thisitem) { 43427261Sminshall if (wewant(thisitem)) { 43527261Sminshall int length; 43627261Sminshall 43727261Sminshall next = thisitem; 43827261Sminshall do { 43927261Sminshall next = nextitem(next); 44027261Sminshall } while (wewant(next) && (nfrontp > next)); 44127261Sminshall length = next-thisitem; 44227261Sminshall bcopy(thisitem, good, length); 44327261Sminshall good += length; 44427261Sminshall thisitem = next; 44527261Sminshall } else { 44627261Sminshall thisitem = nextitem(thisitem); 44727261Sminshall } 44827261Sminshall } 44927261Sminshall 45027261Sminshall nbackp = netobuf; 45127261Sminshall nfrontp = good; /* next byte to be sent */ 45227261Sminshall neturg = 0; 45327261Sminshall } 45427261Sminshall 45527261Sminshall /* 45627186Sminshall * Send as much data as possible to the terminal. 45727186Sminshall */ 45827186Sminshall 45927186Sminshall 46027186Sminshall ttyflush() 46127186Sminshall { 46227186Sminshall int n; 46327186Sminshall 46427186Sminshall if ((n = tfrontp - tbackp) > 0) { 46527228Sminshall if (!(SYNCHing||flushout)) { 46627186Sminshall n = write(tout, tbackp, n); 46727186Sminshall } else { 46827186Sminshall ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 46927228Sminshall /* we leave 'n' alone! */ 47027186Sminshall } 47127186Sminshall } 47227186Sminshall if (n < 0) { 47327186Sminshall return; 47427186Sminshall } 47527186Sminshall tbackp += n; 47627186Sminshall if (tbackp == tfrontp) { 47727186Sminshall tbackp = tfrontp = ttyobuf; 47827186Sminshall } 47927186Sminshall } 48027186Sminshall 48127186Sminshall /* 48227110Sminshall * Various signal handling routines. 48327110Sminshall */ 48427110Sminshall 48527110Sminshall deadpeer() 48627110Sminshall { 48727110Sminshall setcommandmode(); 48827110Sminshall longjmp(peerdied, -1); 48927110Sminshall } 49027110Sminshall 49127110Sminshall intr() 49227110Sminshall { 49327261Sminshall if (localchars) { 49427110Sminshall intp(); 49527110Sminshall return; 49627110Sminshall } 49727110Sminshall setcommandmode(); 49827110Sminshall longjmp(toplevel, -1); 49927110Sminshall } 50027110Sminshall 50127110Sminshall intr2() 50227110Sminshall { 50327261Sminshall if (localchars) { 50427110Sminshall sendbrk(); 50527110Sminshall return; 50627110Sminshall } 50727110Sminshall } 50827110Sminshall 50927110Sminshall doescape() 51027110Sminshall { 51127110Sminshall command(0); 51227110Sminshall } 51327110Sminshall 51427110Sminshall /* 51527186Sminshall * The following are routines used to print out debugging information. 51627186Sminshall */ 51727186Sminshall 51827186Sminshall 51927186Sminshall static 52027186Sminshall Dump(direction, buffer, length) 52127186Sminshall char direction; 52227186Sminshall char *buffer; 52327186Sminshall int length; 52427186Sminshall { 52527186Sminshall # define BYTES_PER_LINE 32 52627186Sminshall # define min(x,y) ((x<y)? x:y) 52727186Sminshall char *pThis; 52827186Sminshall int offset; 52927186Sminshall 53027186Sminshall offset = 0; 53127186Sminshall 53227186Sminshall while (length) { 53327186Sminshall /* print one line */ 53427186Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 53527186Sminshall pThis = buffer; 53627186Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 53727186Sminshall while (pThis < buffer) { 53827186Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 53927186Sminshall pThis++; 54027186Sminshall } 54127186Sminshall fprintf(NetTrace, "\n"); 54227186Sminshall length -= BYTES_PER_LINE; 54327186Sminshall offset += BYTES_PER_LINE; 54427186Sminshall if (length < 0) { 54527186Sminshall return; 54627186Sminshall } 54727186Sminshall /* find next unique line */ 54827186Sminshall } 54927186Sminshall } 55027186Sminshall 55127186Sminshall 55227186Sminshall /*VARARGS*/ 55327186Sminshall printoption(direction, fmt, option, what) 55427186Sminshall char *direction, *fmt; 55527186Sminshall int option, what; 55627186Sminshall { 55727186Sminshall if (!showoptions) 55827186Sminshall return; 559*27676Sminshall printf("%s ", direction+1); 56027186Sminshall if (fmt == doopt) 56127186Sminshall fmt = "do"; 56227186Sminshall else if (fmt == dont) 56327186Sminshall fmt = "dont"; 56427186Sminshall else if (fmt == will) 56527186Sminshall fmt = "will"; 56627186Sminshall else if (fmt == wont) 56727186Sminshall fmt = "wont"; 56827186Sminshall else 56927186Sminshall fmt = "???"; 570*27676Sminshall if (option < (sizeof telopts/sizeof telopts[0])) 57127186Sminshall printf("%s %s", fmt, telopts[option]); 57227186Sminshall else 57327186Sminshall printf("%s %d", fmt, option); 57427186Sminshall if (*direction == '<') { 57527186Sminshall printf("\r\n"); 57627186Sminshall return; 57727186Sminshall } 57827186Sminshall printf(" (%s)\r\n", what ? "reply" : "don't reply"); 57927186Sminshall } 58027186Sminshall 58127186Sminshall /* 58227110Sminshall * Mode - set up terminal to a specific mode. 58327110Sminshall */ 58427110Sminshall 5859972Ssam 5866000Sroot mode(f) 5876000Sroot register int f; 5886000Sroot { 5898378Ssam static int prevmode = 0; 59013076Ssam struct tchars *tc; 59113076Ssam struct ltchars *ltc; 59213076Ssam struct sgttyb sb; 59313076Ssam int onoff, old; 59427228Sminshall struct tchars notc2; 59527228Sminshall struct ltchars noltc2; 59627228Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 59727228Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 5986000Sroot 59927110Sminshall globalmode = f; 6008378Ssam if (prevmode == f) 60127186Sminshall return; 6028378Ssam old = prevmode; 6038378Ssam prevmode = f; 60427110Sminshall sb = nttyb; 6056000Sroot switch (f) { 6068378Ssam 6076000Sroot case 0: 6086000Sroot onoff = 0; 6099972Ssam tc = &otc; 61013076Ssam ltc = &oltc; 6116000Sroot break; 6126000Sroot 61327110Sminshall case 1: /* remote character processing, remote echo */ 61427110Sminshall case 2: /* remote character processing, local echo */ 61513076Ssam sb.sg_flags |= CBREAK; 6168378Ssam if (f == 1) 61713076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 6188378Ssam else 61913076Ssam sb.sg_flags |= ECHO|CRMOD; 62013076Ssam sb.sg_erase = sb.sg_kill = -1; 6219972Ssam tc = ¬c; 62227110Sminshall /* 62327110Sminshall * If user hasn't specified one way or the other, 62427110Sminshall * then default to not trapping signals. 62527110Sminshall */ 62627261Sminshall if (!donelclchars) { 62727261Sminshall localchars = 0; 62827228Sminshall } 62927261Sminshall if (localchars) { 63027110Sminshall notc2 = notc; 63127110Sminshall notc2.t_intrc = ntc.t_intrc; 63227110Sminshall notc2.t_quitc = ntc.t_quitc; 63327110Sminshall tc = ¬c2; 63427110Sminshall } else 63527110Sminshall tc = ¬c; 63613076Ssam ltc = &noltc; 6376000Sroot onoff = 1; 6389972Ssam break; 63927110Sminshall case 3: /* local character processing, remote echo */ 64027110Sminshall case 4: /* local character processing, local echo */ 64127110Sminshall case 5: /* local character processing, no echo */ 64227110Sminshall sb.sg_flags &= ~CBREAK; 64327110Sminshall sb.sg_flags |= CRMOD; 64427110Sminshall if (f == 4) 64527110Sminshall sb.sg_flags |= ECHO; 64627110Sminshall else 64727110Sminshall sb.sg_flags &= ~ECHO; 64827228Sminshall notc2 = ntc; 64927228Sminshall tc = ¬c2; 65027228Sminshall noltc2 = oltc; 65127228Sminshall ltc = &noltc2; 65227110Sminshall /* 65327110Sminshall * If user hasn't specified one way or the other, 65427110Sminshall * then default to trapping signals. 65527110Sminshall */ 65627261Sminshall if (!donelclchars) { 65727261Sminshall localchars = 1; 65827228Sminshall } 65927261Sminshall if (localchars) { 66027228Sminshall notc2.t_brkc = nltc.t_flushc; 66127228Sminshall noltc2.t_flushc = -1; 66227228Sminshall } else { 66327110Sminshall notc2.t_intrc = notc2.t_quitc = -1; 66427110Sminshall } 66527110Sminshall noltc2.t_suspc = escape; 66627110Sminshall noltc2.t_dsuspc = -1; 66727110Sminshall onoff = 1; 66827110Sminshall break; 6699972Ssam 6709972Ssam default: 6719972Ssam return; 6726000Sroot } 67313076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 67413076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 67513076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 67627186Sminshall ioctl(fileno(stdin), FIONBIO, (char *)&onoff); 67727186Sminshall ioctl(fileno(stdout), FIONBIO, (char *)&onoff); 67827110Sminshall if (f >= 3) 67927110Sminshall signal(SIGTSTP, doescape); 68027110Sminshall else if (old >= 3) { 68127110Sminshall signal(SIGTSTP, SIG_DFL); 68227110Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 68327110Sminshall } 6846000Sroot } 68527186Sminshall 68627110Sminshall /* 68727110Sminshall * These routines decides on what the mode should be (based on the values 68827110Sminshall * of various global variables). 68927110Sminshall */ 69027110Sminshall 69127178Sminshall char *modedescriptions[] = { 69227178Sminshall "telnet command mode", /* 0 */ 69327178Sminshall "character-at-a-time mode", /* 1 */ 69427178Sminshall "character-at-a-time mode (local echo)", /* 2 */ 69527178Sminshall "line-by-line mode (remote echo)", /* 3 */ 69627178Sminshall "line-by-line mode", /* 4 */ 69727178Sminshall "line-by-line mode (local echoing suppressed)", /* 5 */ 69827178Sminshall }; 69927178Sminshall 70027178Sminshall getconnmode() 70127110Sminshall { 70227110Sminshall static char newmode[8] = { 4, 5, 3, 3, 2, 2, 1, 1 }; 70327186Sminshall int modeindex = 0; 70427110Sminshall 70527110Sminshall if (hisopts[TELOPT_ECHO]) { 70627186Sminshall modeindex += 2; 70727110Sminshall } 70827110Sminshall if (hisopts[TELOPT_SGA]) { 70927186Sminshall modeindex += 4; 71027110Sminshall } 71127186Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 71227186Sminshall modeindex += 1; 71327110Sminshall } 71427186Sminshall return newmode[modeindex]; 71527110Sminshall } 71627110Sminshall 71727178Sminshall setconnmode() 71827178Sminshall { 71927178Sminshall mode(getconnmode()); 72027178Sminshall } 72127110Sminshall 72227178Sminshall 72327110Sminshall setcommandmode() 72427110Sminshall { 72527110Sminshall mode(0); 72627110Sminshall } 72727110Sminshall 7286000Sroot char sibuf[BUFSIZ], *sbp; 7296000Sroot char tibuf[BUFSIZ], *tbp; 7306000Sroot int scc, tcc; 7316000Sroot 73227228Sminshall 7336000Sroot /* 7346000Sroot * Select from tty and network... 7356000Sroot */ 73627088Sminshall telnet() 7376000Sroot { 7386000Sroot register int c; 73927088Sminshall int tin = fileno(stdin); 7406000Sroot int on = 1; 74127261Sminshall fd_set ibits, obits, xbits; 7426000Sroot 74327088Sminshall tout = fileno(stdout); 74427110Sminshall setconnmode(); 74527228Sminshall scc = 0; 74627228Sminshall tcc = 0; 74727261Sminshall FD_ZERO(&ibits); 74827261Sminshall FD_ZERO(&obits); 74927261Sminshall FD_ZERO(&xbits); 75027261Sminshall 75127186Sminshall ioctl(net, FIONBIO, (char *)&on); 752*27676Sminshall #if defined(SO_OOBINLINE) 753*27676Sminshall setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); 754*27676Sminshall #endif /* defined(SO_OOBINLINE) */ 755*27676Sminshall if (telnetport) { 756*27676Sminshall if (!hisopts[TELOPT_SGA]) { 757*27676Sminshall willoption(TELOPT_SGA, 0); 758*27676Sminshall } 759*27676Sminshall if (!myopts[TELOPT_TTYPE]) { 760*27676Sminshall dooption(TELOPT_TTYPE, 0); 761*27676Sminshall } 76227088Sminshall } 7636000Sroot for (;;) { 76427110Sminshall if (scc < 0 && tcc < 0) { 7656000Sroot break; 76627110Sminshall } 76727110Sminshall 76827228Sminshall if (((globalmode < 4) || flushline) && NETBYTES()) { 76927110Sminshall FD_SET(net, &obits); 77027088Sminshall } else { 77127110Sminshall FD_SET(tin, &ibits); 77227088Sminshall } 77327228Sminshall if (TTYBYTES()) { 77427110Sminshall FD_SET(tout, &obits); 77527110Sminshall } else { 77627110Sminshall FD_SET(net, &ibits); 77727110Sminshall } 77827186Sminshall if (!SYNCHing) { 77927110Sminshall FD_SET(net, &xbits); 78027110Sminshall } 78127186Sminshall if ((c = select(16, &ibits, &obits, &xbits, 78227186Sminshall (struct timeval *)0)) < 1) { 78327110Sminshall if (c == -1) { 78427110Sminshall /* 78527110Sminshall * we can get EINTR if we are in line mode, 78627110Sminshall * and the user does an escape (TSTP), or 78727110Sminshall * some other signal generator. 78827110Sminshall */ 78927110Sminshall if (errno == EINTR) { 79027110Sminshall continue; 79127110Sminshall } 79227110Sminshall } 7936000Sroot sleep(5); 7946000Sroot continue; 7956000Sroot } 7966000Sroot 7976000Sroot /* 79827088Sminshall * Any urgent data? 79927088Sminshall */ 80027110Sminshall if (FD_ISSET(net, &xbits)) { 80127261Sminshall FD_CLR(net, &xbits); 80227186Sminshall SYNCHing = 1; 80327088Sminshall ttyflush(); /* flush already enqueued data */ 80427088Sminshall } 80527088Sminshall 80627088Sminshall /* 8076000Sroot * Something to read from the network... 8086000Sroot */ 80927110Sminshall if (FD_ISSET(net, &ibits)) { 81027228Sminshall int canread; 81127228Sminshall 81227261Sminshall FD_CLR(net, &ibits); 81327228Sminshall if (scc == 0) { 81427228Sminshall sbp = sibuf; 81527228Sminshall } 81627228Sminshall canread = sibuf + sizeof sibuf - sbp; 817*27676Sminshall #if !defined(SO_OOBINLINE) 81827178Sminshall /* 81927178Sminshall * In 4.2 (and some early 4.3) systems, the 82027178Sminshall * OOB indication and data handling in the kernel 82127178Sminshall * is such that if two separate TCP Urgent requests 82227178Sminshall * come in, one byte of TCP data will be overlaid. 82327178Sminshall * This is fatal for Telnet, but we try to live 82427178Sminshall * with it. 82527178Sminshall * 82627178Sminshall * In addition, in 4.2 (and...), a special protocol 82727178Sminshall * is needed to pick up the TCP Urgent data in 82827178Sminshall * the correct sequence. 82927178Sminshall * 83027178Sminshall * What we do is: if we think we are in urgent 83127178Sminshall * mode, we look to see if we are "at the mark". 83227178Sminshall * If we are, we do an OOB receive. If we run 83327178Sminshall * this twice, we will do the OOB receive twice, 83427178Sminshall * but the second will fail, since the second 83527178Sminshall * time we were "at the mark", but there wasn't 83627178Sminshall * any data there (the kernel doesn't reset 83727178Sminshall * "at the mark" until we do a normal read). 83827178Sminshall * Once we've read the OOB data, we go ahead 83927178Sminshall * and do normal reads. 84027178Sminshall * 84127178Sminshall * There is also another problem, which is that 84227178Sminshall * since the OOB byte we read doesn't put us 84327178Sminshall * out of OOB state, and since that byte is most 84427178Sminshall * likely the TELNET DM (data mark), we would 84527186Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 84627178Sminshall * So, clocks to the rescue. If we've "just" 84727178Sminshall * received a DM, then we test for the 84827178Sminshall * presence of OOB data when the receive OOB 84927178Sminshall * fails (and AFTER we did the normal mode read 85027178Sminshall * to clear "at the mark"). 85127178Sminshall */ 85227186Sminshall if (SYNCHing) { 85327178Sminshall int atmark; 85427178Sminshall 85527186Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 85627178Sminshall if (atmark) { 85727228Sminshall c = recv(net, sibuf, canread, MSG_OOB); 85827228Sminshall if ((c == -1) && (errno == EINVAL)) { 85927228Sminshall c = read(net, sibuf, canread); 86027186Sminshall if (clocks.didnetreceive < clocks.gotDM) { 86127186Sminshall SYNCHing = stilloob(net); 86227021Sminshall } 86327178Sminshall } 86427178Sminshall } else { 86527228Sminshall c = read(net, sibuf, canread); 8666000Sroot } 86727178Sminshall } else { 86827228Sminshall c = read(net, sibuf, canread); 86927178Sminshall } 87027178Sminshall settimer(didnetreceive); 871*27676Sminshall #else /* !defined(SO_OOBINLINE) */ 87227228Sminshall c = read(net, sbp, canread); 873*27676Sminshall #endif /* !defined(SO_OOBINLINE) */ 87427228Sminshall if (c < 0 && errno == EWOULDBLOCK) { 87527228Sminshall c = 0; 87627228Sminshall } else if (c <= 0) { 87727228Sminshall break; 87827178Sminshall } 87927228Sminshall if (netdata) { 88027228Sminshall Dump('<', sbp, c); 88127228Sminshall } 88227228Sminshall scc += c; 8836000Sroot } 8846000Sroot 8856000Sroot /* 8866000Sroot * Something to read from the tty... 8876000Sroot */ 88827110Sminshall if (FD_ISSET(tin, &ibits)) { 88927261Sminshall FD_CLR(tin, &ibits); 89027228Sminshall if (tcc == 0) { 89127228Sminshall tbp = tibuf; /* nothing left, reset */ 8926000Sroot } 89327228Sminshall c = read(tin, tbp, tibuf+sizeof tibuf - tbp); 89427228Sminshall if (c < 0 && errno == EWOULDBLOCK) { 89527228Sminshall c = 0; 896*27676Sminshall } else { 897*27676Sminshall /* EOF detection for line mode!!!! */ 898*27676Sminshall if (c == 0 && globalmode >= 3) { 899*27676Sminshall /* must be an EOF... */ 900*27676Sminshall *tbp = ntc.t_eofc; 901*27676Sminshall c = 1; 902*27676Sminshall } 903*27676Sminshall if (c <= 0) { 904*27676Sminshall tcc = c; 905*27676Sminshall break; 906*27676Sminshall } 90727228Sminshall } 90827228Sminshall tcc += c; 9096000Sroot } 9106000Sroot 9116000Sroot while (tcc > 0) { 91227186Sminshall register int sc; 9136000Sroot 91427228Sminshall if (NETROOM() < 2) { 91527110Sminshall flushline = 1; 9166000Sroot break; 91727110Sminshall } 91827186Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 91927186Sminshall if (sc == escape) { 9206000Sroot command(0); 9216000Sroot tcc = 0; 92227110Sminshall flushline = 1; 9236000Sroot break; 92427261Sminshall } else if ((globalmode >= 4) && (sc == echoc)) { 92527110Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 92627110Sminshall tbp++; 92727110Sminshall tcc--; 92827110Sminshall } else { 92927110Sminshall dontlecho = !dontlecho; 93027110Sminshall settimer(echotoggle); 93127110Sminshall setconnmode(); 93227110Sminshall tcc = 0; 93327110Sminshall flushline = 1; 93427110Sminshall break; 93527110Sminshall } 9366000Sroot } 93727261Sminshall if (localchars) { 93827186Sminshall if (sc == ntc.t_intrc) { 93927110Sminshall intp(); 94027110Sminshall break; 94127186Sminshall } else if (sc == ntc.t_quitc) { 94227110Sminshall sendbrk(); 94327110Sminshall break; 94427228Sminshall } else if (sc == nltc.t_flushc) { 94527228Sminshall NET2ADD(IAC, AO); 94627228Sminshall if (autoflush) { 94727228Sminshall doflush(); 94827228Sminshall } 94927228Sminshall break; 95027110Sminshall } else if (globalmode > 2) { 95127110Sminshall ; 95227186Sminshall } else if (sc == nttyb.sg_kill) { 95327110Sminshall NET2ADD(IAC, EL); 95427110Sminshall break; 95527186Sminshall } else if (sc == nttyb.sg_erase) { 95627110Sminshall NET2ADD(IAC, EC); 95727110Sminshall break; 95827110Sminshall } 95927110Sminshall } 96017922Sralph switch (c) { 96117922Sralph case '\n': 96227021Sminshall /* 96327021Sminshall * If echoing is happening locally, 96427021Sminshall * then a newline (unix) is CRLF (TELNET). 96527021Sminshall */ 96627088Sminshall if (!hisopts[TELOPT_ECHO]) { 96727088Sminshall NETADD('\r'); 96827088Sminshall } 96927088Sminshall NETADD('\n'); 97027110Sminshall flushline = 1; 97117922Sralph break; 97217922Sralph case '\r': 97327088Sminshall NET2ADD('\r', '\0'); 97427110Sminshall flushline = 1; 97517922Sralph break; 97617922Sralph case IAC: 97727088Sminshall NET2ADD(IAC, IAC); 97827021Sminshall break; 97917922Sralph default: 98027088Sminshall NETADD(c); 98117922Sralph break; 98217922Sralph } 9836000Sroot } 98427110Sminshall if (((globalmode < 4) || flushline) && 98527228Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 98627261Sminshall FD_CLR(net, &obits); 98727088Sminshall netflush(net); 98827110Sminshall } 9896000Sroot if (scc > 0) 9906000Sroot telrcv(); 99127261Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) { 99227261Sminshall FD_CLR(tout, &obits); 99327088Sminshall ttyflush(); 99427261Sminshall } 9956000Sroot } 99627110Sminshall setcommandmode(); 9976000Sroot } 99827110Sminshall 9996000Sroot /* 10006000Sroot * Telnet receiver states for fsm 10016000Sroot */ 10026000Sroot #define TS_DATA 0 10036000Sroot #define TS_IAC 1 10046000Sroot #define TS_WILL 2 10056000Sroot #define TS_WONT 3 10066000Sroot #define TS_DO 4 10076000Sroot #define TS_DONT 5 100827021Sminshall #define TS_CR 6 1009*27676Sminshall #define TS_SB 7 /* sub-option collection */ 1010*27676Sminshall #define TS_SE 8 /* looking for sub-option end */ 10116000Sroot 10126000Sroot telrcv() 10136000Sroot { 10146000Sroot register int c; 10156000Sroot static int state = TS_DATA; 10166000Sroot 101727228Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 101827186Sminshall c = *sbp++ & 0xff, scc--; 10196000Sroot switch (state) { 10206000Sroot 102127021Sminshall case TS_CR: 102227021Sminshall state = TS_DATA; 102327228Sminshall if (c == '\0') { 102427228Sminshall break; /* Ignore \0 after CR */ 102527228Sminshall } else if (c == '\n') { 102627228Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 102727228Sminshall TTYADD(c); 102827228Sminshall } 102927228Sminshall break; 103027021Sminshall } 103127228Sminshall /* Else, fall through */ 103227021Sminshall 10336000Sroot case TS_DATA: 10349972Ssam if (c == IAC) { 10356000Sroot state = TS_IAC; 10369972Ssam continue; 10379972Ssam } 103827228Sminshall /* 103927228Sminshall * The 'crmod' hack (see following) is needed 104027228Sminshall * since we can't * set CRMOD on output only. 104127228Sminshall * Machines like MULTICS like to send \r without 104227228Sminshall * \n; since we must turn off CRMOD to get proper 104327228Sminshall * input, the mapping is done here (sigh). 104427228Sminshall */ 104527021Sminshall if (c == '\r') { 104627021Sminshall if (scc > 0) { 104727186Sminshall c = *sbp&0xff; 104827021Sminshall if (c == 0) { 104927021Sminshall sbp++, scc--; 105027228Sminshall /* a "true" CR */ 105127088Sminshall TTYADD('\r'); 105227021Sminshall } else if (!hisopts[TELOPT_ECHO] && 105327021Sminshall (c == '\n')) { 105427021Sminshall sbp++, scc--; 105527088Sminshall TTYADD('\n'); 105627021Sminshall } else { 105727088Sminshall TTYADD('\r'); 105827228Sminshall if (crmod) { 105927228Sminshall TTYADD('\n'); 106027228Sminshall } 106127021Sminshall } 106227021Sminshall } else { 106327021Sminshall state = TS_CR; 106427088Sminshall TTYADD('\r'); 106527228Sminshall if (crmod) { 106627228Sminshall TTYADD('\n'); 106727228Sminshall } 106827021Sminshall } 106927021Sminshall } else { 107027088Sminshall TTYADD(c); 107127021Sminshall } 10726000Sroot continue; 10736000Sroot 10746000Sroot case TS_IAC: 10756000Sroot switch (c) { 10766000Sroot 10776000Sroot case WILL: 10786000Sroot state = TS_WILL; 10796000Sroot continue; 10806000Sroot 10816000Sroot case WONT: 10826000Sroot state = TS_WONT; 10836000Sroot continue; 10846000Sroot 10856000Sroot case DO: 10866000Sroot state = TS_DO; 10876000Sroot continue; 10886000Sroot 10896000Sroot case DONT: 10906000Sroot state = TS_DONT; 10916000Sroot continue; 10926000Sroot 10936000Sroot case DM: 109427088Sminshall /* 109527088Sminshall * We may have missed an urgent notification, 109627088Sminshall * so make sure we flush whatever is in the 109727088Sminshall * buffer currently. 109827088Sminshall */ 109927186Sminshall SYNCHing = 1; 110027088Sminshall ttyflush(); 110127186Sminshall SYNCHing = stilloob(net); 110227178Sminshall settimer(gotDM); 11036000Sroot break; 11046000Sroot 11056000Sroot case NOP: 11066000Sroot case GA: 11076000Sroot break; 11086000Sroot 1109*27676Sminshall case SB: 1110*27676Sminshall SB_CLEAR(); 1111*27676Sminshall state = TS_SB; 1112*27676Sminshall continue; 1113*27676Sminshall 11146000Sroot default: 11156000Sroot break; 11166000Sroot } 11176000Sroot state = TS_DATA; 11186000Sroot continue; 11196000Sroot 11206000Sroot case TS_WILL: 1121*27676Sminshall printoption(">RCVD", will, c, !hisopts[c]); 112227110Sminshall if (c == TELOPT_TM) { 112327110Sminshall if (flushout) { 112427186Sminshall flushout = 0; 112527110Sminshall } 112627110Sminshall } else if (!hisopts[c]) { 1127*27676Sminshall willoption(c, 1); 112827110Sminshall } 11296000Sroot state = TS_DATA; 11306000Sroot continue; 11316000Sroot 11326000Sroot case TS_WONT: 1133*27676Sminshall printoption(">RCVD", wont, c, hisopts[c]); 113427110Sminshall if (c == TELOPT_TM) { 113527110Sminshall if (flushout) { 113627186Sminshall flushout = 0; 113727110Sminshall } 113827110Sminshall } else if (hisopts[c]) { 1139*27676Sminshall wontoption(c, 1); 114027110Sminshall } 11416000Sroot state = TS_DATA; 11426000Sroot continue; 11436000Sroot 11446000Sroot case TS_DO: 1145*27676Sminshall printoption(">RCVD", doopt, c, !myopts[c]); 11466000Sroot if (!myopts[c]) 11476000Sroot dooption(c); 11486000Sroot state = TS_DATA; 11496000Sroot continue; 11506000Sroot 11516000Sroot case TS_DONT: 1152*27676Sminshall printoption(">RCVD", dont, c, myopts[c]); 11536000Sroot if (myopts[c]) { 11546000Sroot myopts[c] = 0; 11556000Sroot sprintf(nfrontp, wont, c); 11568378Ssam nfrontp += sizeof (wont) - 2; 115727110Sminshall flushline = 1; 115827110Sminshall setconnmode(); /* set new tty mode (maybe) */ 1159*27676Sminshall printoption(">SENT", wont, c); 11606000Sroot } 11616000Sroot state = TS_DATA; 11626000Sroot continue; 1163*27676Sminshall case TS_SB: 1164*27676Sminshall if (c == IAC) { 1165*27676Sminshall state = TS_SE; 1166*27676Sminshall } else { 1167*27676Sminshall SB_ACCUM(c); 1168*27676Sminshall } 1169*27676Sminshall continue; 1170*27676Sminshall 1171*27676Sminshall case TS_SE: 1172*27676Sminshall if (c != SE) { 1173*27676Sminshall if (c != IAC) { 1174*27676Sminshall SB_ACCUM(IAC); 1175*27676Sminshall } 1176*27676Sminshall SB_ACCUM(c); 1177*27676Sminshall state = TS_SB; 1178*27676Sminshall } else { 1179*27676Sminshall SB_TERM(); 1180*27676Sminshall suboption(); /* handle sub-option */ 1181*27676Sminshall state = TS_DATA; 1182*27676Sminshall } 11836000Sroot } 11846000Sroot } 11856000Sroot } 118627110Sminshall 1187*27676Sminshall willoption(option, reply) 1188*27676Sminshall int option, reply; 11896000Sroot { 11906000Sroot char *fmt; 11916000Sroot 11926000Sroot switch (option) { 11936000Sroot 11946000Sroot case TELOPT_ECHO: 11956000Sroot case TELOPT_SGA: 119627110Sminshall settimer(modenegotiated); 11976000Sroot hisopts[option] = 1; 11986000Sroot fmt = doopt; 119927110Sminshall setconnmode(); /* possibly set new tty mode */ 12006000Sroot break; 12016000Sroot 12026000Sroot case TELOPT_TM: 120327110Sminshall return; /* Never reply to TM will's/wont's */ 12046000Sroot 12056000Sroot default: 12066000Sroot fmt = dont; 12076000Sroot break; 12086000Sroot } 12096024Ssam sprintf(nfrontp, fmt, option); 12108378Ssam nfrontp += sizeof (dont) - 2; 1211*27676Sminshall if (reply) 1212*27676Sminshall printoption(">SENT", fmt, option); 1213*27676Sminshall else 1214*27676Sminshall printoption("<SENT", fmt, option); 12156000Sroot } 12166000Sroot 1217*27676Sminshall wontoption(option, reply) 1218*27676Sminshall int option, reply; 12196000Sroot { 12206000Sroot char *fmt; 12216000Sroot 12226000Sroot switch (option) { 12236000Sroot 12246000Sroot case TELOPT_ECHO: 12256000Sroot case TELOPT_SGA: 122627110Sminshall settimer(modenegotiated); 12276000Sroot hisopts[option] = 0; 12286000Sroot fmt = dont; 122927110Sminshall setconnmode(); /* Set new tty mode */ 12306000Sroot break; 12316000Sroot 123227110Sminshall case TELOPT_TM: 123327110Sminshall return; /* Never reply to TM will's/wont's */ 123427110Sminshall 12356000Sroot default: 12366000Sroot fmt = dont; 12376000Sroot } 12386000Sroot sprintf(nfrontp, fmt, option); 12398378Ssam nfrontp += sizeof (doopt) - 2; 1240*27676Sminshall if (reply) 1241*27676Sminshall printoption(">SENT", fmt, option); 1242*27676Sminshall else 1243*27676Sminshall printoption("<SENT", fmt, option); 12446000Sroot } 12456000Sroot 12466000Sroot dooption(option) 12476000Sroot int option; 12486000Sroot { 12496000Sroot char *fmt; 12506000Sroot 12516000Sroot switch (option) { 12526000Sroot 12536000Sroot case TELOPT_TM: 125413231Ssam fmt = will; 125513231Ssam break; 125613231Ssam 1257*27676Sminshall case TELOPT_TTYPE: /* terminal type option */ 125827110Sminshall case TELOPT_SGA: /* no big deal */ 12596000Sroot fmt = will; 126027110Sminshall myopts[option] = 1; 12616000Sroot break; 12626000Sroot 126327110Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 12646000Sroot default: 12656000Sroot fmt = wont; 12666000Sroot break; 12676000Sroot } 12686000Sroot sprintf(nfrontp, fmt, option); 12698378Ssam nfrontp += sizeof (doopt) - 2; 1270*27676Sminshall printoption(">SENT", fmt, option); 12716000Sroot } 1272*27676Sminshall 1273*27676Sminshall /* 1274*27676Sminshall * suboption() 1275*27676Sminshall * 1276*27676Sminshall * Look at the sub-option buffer, and try to be helpful to the other 1277*27676Sminshall * side. 1278*27676Sminshall * 1279*27676Sminshall * Currently we recognize: 1280*27676Sminshall * 1281*27676Sminshall * Terminal type, send request. 1282*27676Sminshall */ 1283*27676Sminshall 1284*27676Sminshall suboption() 1285*27676Sminshall { 1286*27676Sminshall switch (subbuffer[0]&0xff) { 1287*27676Sminshall case TELOPT_TTYPE: 1288*27676Sminshall if ((subbuffer[1]&0xff) != TELQUAL_SEND) { 1289*27676Sminshall ; 1290*27676Sminshall } else { 1291*27676Sminshall char *name; 1292*27676Sminshall char namebuf[41]; 1293*27676Sminshall char *getenv(); 1294*27676Sminshall int len; 1295*27676Sminshall 1296*27676Sminshall name = getenv("TERM"); 1297*27676Sminshall if ((name == 0) || ((len = strlen(name)) > 40)) { 1298*27676Sminshall name = "UNKNOWN"; 1299*27676Sminshall } 1300*27676Sminshall if ((len + 4+2) < NETROOM()) { 1301*27676Sminshall strcpy(namebuf, name); 1302*27676Sminshall upcase(namebuf); 1303*27676Sminshall sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 1304*27676Sminshall TELQUAL_IS, namebuf, IAC, SE); 1305*27676Sminshall nfrontp += 4+strlen(namebuf)+2; 1306*27676Sminshall } 1307*27676Sminshall } 1308*27676Sminshall 1309*27676Sminshall default: 1310*27676Sminshall break; 1311*27676Sminshall } 1312*27676Sminshall } 131327110Sminshall 13146000Sroot /* 131527088Sminshall * The following are data structures and routines for 131627088Sminshall * the "send" command. 131727088Sminshall * 131827088Sminshall */ 131927088Sminshall 132027088Sminshall struct sendlist { 132127088Sminshall char *name; /* How user refers to it (case independent) */ 132227088Sminshall int what; /* Character to be sent (<0 ==> special) */ 132327088Sminshall char *help; /* Help information (0 ==> no help) */ 132427088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 132527088Sminshall }; 132627088Sminshall 132727186Sminshall /*ARGSUSED*/ 132827088Sminshall dosynch(s) 132927088Sminshall struct sendlist *s; 133027088Sminshall { 133127261Sminshall netclear(); /* clear the path to the network */ 133227088Sminshall NET2ADD(IAC, DM); 133327186Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 133427088Sminshall } 133527088Sminshall 133627228Sminshall doflush() 133727228Sminshall { 133827228Sminshall NET2ADD(IAC, DO); 133927228Sminshall NETADD(TELOPT_TM); 134027228Sminshall flushline = 1; 134127228Sminshall flushout = 1; 134227228Sminshall ttyflush(); 1343*27676Sminshall /* do printoption AFTER flush, otherwise the output gets tossed... */ 1344*27676Sminshall printoption("<SENT", doopt, TELOPT_TM); 134527228Sminshall } 134627228Sminshall 134727088Sminshall intp() 134827088Sminshall { 134927110Sminshall NET2ADD(IAC, IP); 135027228Sminshall if (autoflush) { 135127228Sminshall doflush(); 135227228Sminshall } 135327228Sminshall if (autosynch) { 135427228Sminshall dosynch(); 135527228Sminshall } 135627088Sminshall } 135727088Sminshall 135827110Sminshall sendbrk() 135927110Sminshall { 136027186Sminshall NET2ADD(IAC, BREAK); 136127228Sminshall if (autoflush) { 136227228Sminshall doflush(); 136327228Sminshall } 136427228Sminshall if (autosynch) { 136527228Sminshall dosynch(); 136627228Sminshall } 136727110Sminshall } 136827088Sminshall 136927110Sminshall 137027088Sminshall #define SENDQUESTION -1 137127088Sminshall #define SENDESCAPE -3 137227088Sminshall 137327088Sminshall struct sendlist Sendlist[] = { 137427088Sminshall { "ao", AO, "Send Telnet Abort output" }, 137527088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 137627261Sminshall { "brk", BREAK, "Send Telnet Break" }, 137727088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 137827088Sminshall { "el", EL, "Send Telnet Erase Line" }, 137927261Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 138027088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 138127261Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 138227088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 138327261Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 138427088Sminshall { "?", SENDQUESTION, "Display send options" }, 138527088Sminshall { 0 } 138627088Sminshall }; 138727088Sminshall 138827261Sminshall struct sendlist Sendlist2[] = { /* some synonyms */ 138927261Sminshall { "break", BREAK, 0 }, 139027261Sminshall 139127261Sminshall { "intp", IP, 0 }, 139227261Sminshall { "interrupt", IP, 0 }, 139327261Sminshall { "intr", IP, 0 }, 139427261Sminshall 139527261Sminshall { "help", SENDQUESTION, 0 }, 139627261Sminshall 139727261Sminshall { 0 } 139827261Sminshall }; 139927261Sminshall 140027088Sminshall char ** 140127088Sminshall getnextsend(name) 140227088Sminshall char *name; 140327088Sminshall { 140427088Sminshall struct sendlist *c = (struct sendlist *) name; 140527088Sminshall 140627088Sminshall return (char **) (c+1); 140727088Sminshall } 140827088Sminshall 140927088Sminshall struct sendlist * 141027088Sminshall getsend(name) 141127088Sminshall char *name; 141227088Sminshall { 141327261Sminshall struct sendlist *sl; 141427261Sminshall 141527261Sminshall if (sl = (struct sendlist *) 141627261Sminshall genget(name, (char **) Sendlist, getnextsend)) { 141727261Sminshall return sl; 141827261Sminshall } else { 141927261Sminshall return (struct sendlist *) 142027261Sminshall genget(name, (char **) Sendlist2, getnextsend); 142127261Sminshall } 142227088Sminshall } 142327088Sminshall 142427088Sminshall sendcmd(argc, argv) 142527088Sminshall int argc; 142627088Sminshall char **argv; 142727088Sminshall { 142827088Sminshall int what; /* what we are sending this time */ 142927088Sminshall int count; /* how many bytes we are going to need to send */ 143027088Sminshall int hadsynch; /* are we going to process a "synch"? */ 143127088Sminshall int i; 143227261Sminshall int question = 0; /* was at least one argument a question */ 143327088Sminshall struct sendlist *s; /* pointer to current command */ 143427088Sminshall 143527088Sminshall if (argc < 2) { 143627088Sminshall printf("need at least one argument for 'send' command\n"); 143727088Sminshall printf("'send ?' for help\n"); 143827261Sminshall return 0; 143927088Sminshall } 144027088Sminshall /* 144127088Sminshall * First, validate all the send arguments. 144227088Sminshall * In addition, we see how much space we are going to need, and 144327088Sminshall * whether or not we will be doing a "SYNCH" operation (which 144427088Sminshall * flushes the network queue). 144527088Sminshall */ 144627088Sminshall count = 0; 144727088Sminshall hadsynch = 0; 144827088Sminshall for (i = 1; i < argc; i++) { 144927088Sminshall s = getsend(argv[i]); 145027088Sminshall if (s == 0) { 145127088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 145227088Sminshall argv[i]); 145327261Sminshall return 0; 145427186Sminshall } else if (s == Ambiguous(struct sendlist *)) { 145527088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 145627088Sminshall argv[i]); 145727261Sminshall return 0; 145827088Sminshall } 145927088Sminshall switch (s->what) { 146027088Sminshall case SENDQUESTION: 146127088Sminshall break; 146227088Sminshall case SENDESCAPE: 146327088Sminshall count += 1; 146427088Sminshall break; 146527088Sminshall case SYNCH: 146627088Sminshall hadsynch = 1; 146727088Sminshall count += 2; 146827088Sminshall break; 146927088Sminshall default: 147027088Sminshall count += 2; 147127088Sminshall break; 147227088Sminshall } 147327088Sminshall } 147427088Sminshall /* Now, do we have enough room? */ 147527228Sminshall if (NETROOM() < count) { 147627088Sminshall printf("There is not enough room in the buffer TO the network\n"); 147727088Sminshall printf("to process your request. Nothing will be done.\n"); 147827088Sminshall printf("('send synch' will throw away most data in the network\n"); 147927088Sminshall printf("buffer, if this might help.)\n"); 148027261Sminshall return 0; 148127088Sminshall } 148227088Sminshall /* OK, they are all OK, now go through again and actually send */ 148327088Sminshall for (i = 1; i < argc; i++) { 148427088Sminshall if (!(s = getsend(argv[i]))) { 148527088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 148627088Sminshall quit(); 148727088Sminshall /*NOTREACHED*/ 148827088Sminshall } 148927088Sminshall if (s->routine) { 149027088Sminshall (*s->routine)(s); 149127088Sminshall } else { 149227088Sminshall switch (what = s->what) { 149327261Sminshall case SYNCH: 149427261Sminshall dosynch(); 149527261Sminshall break; 149627088Sminshall case SENDQUESTION: 149727088Sminshall for (s = Sendlist; s->name; s++) { 149827261Sminshall if (s->help) { 149927088Sminshall printf(s->name); 150027088Sminshall if (s->help) { 150127088Sminshall printf("\t%s", s->help); 150227088Sminshall } 150327088Sminshall printf("\n"); 150427088Sminshall } 150527088Sminshall } 150627261Sminshall question = 1; 150727088Sminshall break; 150827088Sminshall case SENDESCAPE: 150927088Sminshall NETADD(escape); 151027088Sminshall break; 151127088Sminshall default: 151227088Sminshall NET2ADD(IAC, what); 151327088Sminshall break; 151427088Sminshall } 151527088Sminshall } 151627088Sminshall } 151727261Sminshall return !question; 151827088Sminshall } 151927088Sminshall 152027088Sminshall /* 152127088Sminshall * The following are the routines and data structures referred 152227088Sminshall * to by the arguments to the "toggle" command. 152327088Sminshall */ 152427088Sminshall 152527261Sminshall lclchars() 152627110Sminshall { 152727261Sminshall donelclchars = 1; 152827261Sminshall return 1; 152927110Sminshall } 153027110Sminshall 153127178Sminshall togdebug() 153227088Sminshall { 1533*27676Sminshall #ifndef NOT43 153427110Sminshall if (net > 0 && 153527186Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug)) 153627186Sminshall < 0) { 153727110Sminshall perror("setsockopt (SO_DEBUG)"); 153827186Sminshall } 1539*27676Sminshall #else NOT43 1540*27676Sminshall if (debug) { 1541*27676Sminshall if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 1542*27676Sminshall perror("setsockopt (SO_DEBUG)"); 1543*27676Sminshall } else 1544*27676Sminshall printf("Cannot turn off socket debugging\n"); 1545*27676Sminshall #endif NOT43 154627261Sminshall return 1; 154727088Sminshall } 154827088Sminshall 154927088Sminshall 155027088Sminshall 155127088Sminshall int togglehelp(); 155227088Sminshall 155327178Sminshall struct togglelist { 155427178Sminshall char *name; /* name of toggle */ 155527178Sminshall char *help; /* help message */ 155627186Sminshall int (*handler)(); /* routine to do actual setting */ 155727178Sminshall int dohelp; /* should we display help information */ 155827178Sminshall int *variable; 155927178Sminshall char *actionexplanation; 156027178Sminshall }; 156127178Sminshall 156227178Sminshall struct togglelist Togglelist[] = { 156327261Sminshall { "autoflush", 156427261Sminshall "toggle flushing of output when sending interrupt characters", 156527186Sminshall 0, 156627178Sminshall 1, 156727261Sminshall &autoflush, 156827261Sminshall "flush output when sending interrupt characters" }, 156927186Sminshall { "autosynch", 157027186Sminshall "toggle automatic sending of interrupt characters in urgent mode", 157127186Sminshall 0, 157227186Sminshall 1, 157327186Sminshall &autosynch, 157427186Sminshall "send interrupt characters in urgent mode" }, 157527178Sminshall { "crmod", 157627261Sminshall "toggle mapping of received carriage returns", 157727186Sminshall 0, 157827178Sminshall 1, 157927178Sminshall &crmod, 158027178Sminshall "map carriage return on output" }, 158127261Sminshall { "localchars", 158227261Sminshall "toggle local recognition of certain control characters", 158327261Sminshall lclchars, 158427261Sminshall 1, 158527261Sminshall &localchars, 158627261Sminshall "recognize certain control characters" }, 158727110Sminshall { " ", "", 0, 1 }, /* empty line */ 158827178Sminshall { "debug", 158927178Sminshall "(debugging) toggle debugging", 159027178Sminshall togdebug, 159127178Sminshall 1, 159227178Sminshall &debug, 159327178Sminshall "turn on socket level debugging" }, 159427261Sminshall { "netdata", 159527261Sminshall "(debugging) toggle printing of hexadecimal network data", 159627261Sminshall 0, 159727261Sminshall 1, 159827261Sminshall &netdata, 159927261Sminshall "print hexadecimal representation of network traffic" }, 160027178Sminshall { "options", 160127178Sminshall "(debugging) toggle viewing of options processing", 160227186Sminshall 0, 160327178Sminshall 1, 160427178Sminshall &showoptions, 160527178Sminshall "show option processing" }, 160627261Sminshall { " ", "", 0, 1 }, /* empty line */ 160727178Sminshall { "?", 160827178Sminshall "display help information", 160927178Sminshall togglehelp, 161027178Sminshall 1 }, 161127178Sminshall { "help", 161227178Sminshall "display help information", 161327178Sminshall togglehelp, 161427178Sminshall 0 }, 161527088Sminshall { 0 } 161627088Sminshall }; 161727088Sminshall 161827088Sminshall togglehelp() 161927088Sminshall { 162027178Sminshall struct togglelist *c; 162127088Sminshall 162227178Sminshall for (c = Togglelist; c->name; c++) { 162327088Sminshall if (c->dohelp) { 162427088Sminshall printf("%s\t%s\n", c->name, c->help); 162527088Sminshall } 162627088Sminshall } 162727261Sminshall return 0; 162827088Sminshall } 162927088Sminshall 163027088Sminshall char ** 163127088Sminshall getnexttoggle(name) 163227088Sminshall char *name; 163327088Sminshall { 163427178Sminshall struct togglelist *c = (struct togglelist *) name; 163527088Sminshall 163627088Sminshall return (char **) (c+1); 163727088Sminshall } 163827088Sminshall 163927178Sminshall struct togglelist * 164027088Sminshall gettoggle(name) 164127088Sminshall char *name; 164227088Sminshall { 164327178Sminshall return (struct togglelist *) 164427178Sminshall genget(name, (char **) Togglelist, getnexttoggle); 164527088Sminshall } 164627088Sminshall 164727088Sminshall toggle(argc, argv) 164827088Sminshall int argc; 164927088Sminshall char *argv[]; 165027088Sminshall { 165127261Sminshall int retval = 1; 165227088Sminshall char *name; 165327178Sminshall struct togglelist *c; 165427088Sminshall 165527088Sminshall if (argc < 2) { 165627088Sminshall fprintf(stderr, 165727088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 165827261Sminshall return 0; 165927088Sminshall } 166027088Sminshall argc--; 166127088Sminshall argv++; 166227088Sminshall while (argc--) { 166327088Sminshall name = *argv++; 166427088Sminshall c = gettoggle(name); 166527186Sminshall if (c == Ambiguous(struct togglelist *)) { 166627088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 166727088Sminshall name); 166827261Sminshall return 0; 166927088Sminshall } else if (c == 0) { 167027088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 167127088Sminshall name); 167227261Sminshall return 0; 167327088Sminshall } else { 167427186Sminshall if (c->variable) { 167527186Sminshall *c->variable = !*c->variable; /* invert it */ 167627186Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 167727186Sminshall c->actionexplanation); 167827186Sminshall } 167927186Sminshall if (c->handler) { 168027261Sminshall retval &= (*c->handler)(c); 168127186Sminshall } 168227088Sminshall } 168327088Sminshall } 168427261Sminshall return retval; 168527088Sminshall } 168627088Sminshall 168727088Sminshall /* 168827110Sminshall * The following perform the "set" command. 168927110Sminshall */ 169027110Sminshall 169127178Sminshall struct setlist { 169227178Sminshall char *name; /* name */ 169327110Sminshall char *help; /* help information */ 169427110Sminshall char *charp; /* where it is located at */ 169527110Sminshall }; 169627110Sminshall 169727178Sminshall struct setlist Setlist[] = { 169827110Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 169927110Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 170027261Sminshall { " ", "" }, 170127261Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 170227261Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 170327261Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 170427110Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 170527261Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 170627110Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 1707*27676Sminshall { "eof", "character to cause an EOF ", &ntc.t_eofc }, 170827110Sminshall { 0 } 170927110Sminshall }; 171027110Sminshall 171127110Sminshall char ** 171227178Sminshall getnextset(name) 171327110Sminshall char *name; 171427110Sminshall { 171527178Sminshall struct setlist *c = (struct setlist *)name; 171627110Sminshall 171727110Sminshall return (char **) (c+1); 171827110Sminshall } 171927110Sminshall 172027178Sminshall struct setlist * 172127178Sminshall getset(name) 172227110Sminshall char *name; 172327110Sminshall { 172427178Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 172527110Sminshall } 172627110Sminshall 172727110Sminshall setcmd(argc, argv) 172827110Sminshall int argc; 172927110Sminshall char *argv[]; 173027110Sminshall { 173127110Sminshall int value; 173227178Sminshall struct setlist *ct; 173327110Sminshall 173427110Sminshall /* XXX back we go... sigh */ 173527110Sminshall if (argc != 3) { 173627261Sminshall if ((argc == 2) && 173727261Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 173827261Sminshall for (ct = Setlist; ct->name; ct++) { 173927261Sminshall printf("%s\t%s\n", ct->name, ct->help); 174027261Sminshall } 174127261Sminshall printf("?\tdisplay help information\n"); 174227261Sminshall } else { 174327261Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 174427110Sminshall } 174527261Sminshall return 0; 174627110Sminshall } 174727110Sminshall 174827178Sminshall ct = getset(argv[1]); 174927110Sminshall if (ct == 0) { 175027110Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 175127110Sminshall argv[1]); 175227261Sminshall return 0; 175327186Sminshall } else if (ct == Ambiguous(struct setlist *)) { 175427110Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 175527110Sminshall argv[1]); 175627261Sminshall return 0; 175727110Sminshall } else { 175827110Sminshall if (strcmp("off", argv[2])) { 175927110Sminshall value = special(argv[2]); 176027110Sminshall } else { 176127110Sminshall value = -1; 176227110Sminshall } 176327110Sminshall *(ct->charp) = value; 176427178Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 176527110Sminshall } 176627261Sminshall return 1; 176727110Sminshall } 176827110Sminshall 176927110Sminshall /* 177027110Sminshall * The following are the data structures and routines for the 177127110Sminshall * 'mode' command. 177227110Sminshall */ 177327110Sminshall 177427110Sminshall dolinemode() 177527110Sminshall { 177627110Sminshall if (hisopts[TELOPT_SGA]) { 1777*27676Sminshall wontoption(TELOPT_SGA, 0); 177827110Sminshall } 177927110Sminshall if (hisopts[TELOPT_ECHO]) { 1780*27676Sminshall wontoption(TELOPT_ECHO, 0); 178127110Sminshall } 178227110Sminshall } 178327110Sminshall 178427110Sminshall docharmode() 178527110Sminshall { 178627110Sminshall if (!hisopts[TELOPT_SGA]) { 1787*27676Sminshall willoption(TELOPT_SGA, 0); 178827110Sminshall } 178927110Sminshall if (!hisopts[TELOPT_ECHO]) { 1790*27676Sminshall willoption(TELOPT_ECHO, 0); 179127110Sminshall } 179227110Sminshall } 179327110Sminshall 179427110Sminshall struct cmd Modelist[] = { 179527261Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 179627110Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 179727110Sminshall { 0 }, 179827110Sminshall }; 179927110Sminshall 180027110Sminshall char ** 180127110Sminshall getnextmode(name) 180227110Sminshall char *name; 180327110Sminshall { 180427110Sminshall struct cmd *c = (struct cmd *) name; 180527110Sminshall 180627110Sminshall return (char **) (c+1); 180727110Sminshall } 180827110Sminshall 180927110Sminshall struct cmd * 181027110Sminshall getmodecmd(name) 181127110Sminshall char *name; 181227110Sminshall { 181327110Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 181427110Sminshall } 181527110Sminshall 181627110Sminshall modecmd(argc, argv) 181727110Sminshall int argc; 181827110Sminshall char *argv[]; 181927110Sminshall { 182027110Sminshall struct cmd *mt; 182127110Sminshall 182227110Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 182327110Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 182427110Sminshall for (mt = Modelist; mt->name; mt++) { 182527110Sminshall printf("%s\t%s\n", mt->name, mt->help); 182627110Sminshall } 182727261Sminshall return 0; 182827110Sminshall } 182927110Sminshall mt = getmodecmd(argv[1]); 183027110Sminshall if (mt == 0) { 183127110Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 183227261Sminshall return 0; 183327186Sminshall } else if (mt == Ambiguous(struct cmd *)) { 183427110Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 183527261Sminshall return 0; 183627110Sminshall } else { 183727110Sminshall (*mt->handler)(); 183827110Sminshall } 183927261Sminshall return 1; 184027110Sminshall } 184127110Sminshall 184227110Sminshall /* 184327178Sminshall * The following data structures and routines implement the 184427178Sminshall * "display" command. 184527178Sminshall */ 184627178Sminshall 184727178Sminshall display(argc, argv) 184827178Sminshall int argc; 184927178Sminshall char *argv[]; 185027178Sminshall { 185127178Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 185227178Sminshall if (*tl->variable) { \ 185327178Sminshall printf("will"); \ 185427178Sminshall } else { \ 185527178Sminshall printf("won't"); \ 185627178Sminshall } \ 185727178Sminshall printf(" %s.\n", tl->actionexplanation); \ 185827178Sminshall } 185927178Sminshall 186027261Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 186127261Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 186227261Sminshall } 186327178Sminshall 186427178Sminshall struct togglelist *tl; 186527178Sminshall struct setlist *sl; 186627178Sminshall 186727178Sminshall if (argc == 1) { 186827178Sminshall for (tl = Togglelist; tl->name; tl++) { 186927178Sminshall dotog(tl); 187027178Sminshall } 187127261Sminshall printf("\n"); 187227178Sminshall for (sl = Setlist; sl->name; sl++) { 187327178Sminshall doset(sl); 187427178Sminshall } 187527178Sminshall } else { 187627178Sminshall int i; 187727178Sminshall 187827178Sminshall for (i = 1; i < argc; i++) { 187927178Sminshall sl = getset(argv[i]); 188027178Sminshall tl = gettoggle(argv[i]); 188127186Sminshall if ((sl == Ambiguous(struct setlist *)) || 188227186Sminshall (tl == Ambiguous(struct togglelist *))) { 188327178Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 188427261Sminshall return 0; 188527178Sminshall } else if (!sl && !tl) { 188627178Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 188727261Sminshall return 0; 188827178Sminshall } else { 188927186Sminshall if (tl) { 189027186Sminshall dotog(tl); 189127186Sminshall } 189227186Sminshall if (sl) { 189327186Sminshall doset(sl); 189427186Sminshall } 189527178Sminshall } 189627178Sminshall } 189727178Sminshall } 189827261Sminshall return 1; 189927178Sminshall #undef doset(sl) 190027178Sminshall #undef dotog(tl) 190127178Sminshall } 190227178Sminshall 190327178Sminshall /* 190427088Sminshall * The following are the data structures, and many of the routines, 190527088Sminshall * relating to command processing. 190627088Sminshall */ 190727088Sminshall 190827088Sminshall /* 190927088Sminshall * Set the escape character. 191027088Sminshall */ 191127088Sminshall setescape(argc, argv) 191227088Sminshall int argc; 191327088Sminshall char *argv[]; 191427088Sminshall { 191527088Sminshall register char *arg; 191627088Sminshall char buf[50]; 191727088Sminshall 191827186Sminshall printf( 191927186Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 192027186Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 192127088Sminshall if (argc > 2) 192227088Sminshall arg = argv[1]; 192327088Sminshall else { 192427088Sminshall printf("new escape character: "); 192527088Sminshall gets(buf); 192627088Sminshall arg = buf; 192727088Sminshall } 192827088Sminshall if (arg[0] != '\0') 192927088Sminshall escape = arg[0]; 193027088Sminshall printf("Escape character is '%s'.\n", control(escape)); 193127088Sminshall fflush(stdout); 193227261Sminshall return 1; 193327088Sminshall } 193427088Sminshall 193527088Sminshall /*VARARGS*/ 193627261Sminshall togcrmod() 193727261Sminshall { 193827261Sminshall crmod = !crmod; 193927261Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 194027261Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 194127261Sminshall fflush(stdout); 194227261Sminshall return 1; 194327261Sminshall } 194427261Sminshall 194527261Sminshall /*VARARGS*/ 194627088Sminshall suspend() 194727088Sminshall { 194827110Sminshall setcommandmode(); 194927088Sminshall kill(0, SIGTSTP); 195027088Sminshall /* reget parameters in case they were changed */ 195127088Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 195227088Sminshall ioctl(0, TIOCGETC, (char *)&otc); 195327088Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 195427261Sminshall return 1; 195527088Sminshall } 195627088Sminshall 195727088Sminshall /*VARARGS*/ 195827088Sminshall bye() 195927088Sminshall { 196027088Sminshall register char *op; 196127088Sminshall 196227088Sminshall if (connected) { 196327088Sminshall shutdown(net, 2); 196427088Sminshall printf("Connection closed.\n"); 196527088Sminshall close(net); 196627088Sminshall connected = 0; 196727088Sminshall /* reset his options */ 196827088Sminshall for (op = hisopts; op < &hisopts[256]; op++) 196927088Sminshall *op = 0; 197027088Sminshall } 197127261Sminshall return 1; 197227088Sminshall } 197327088Sminshall 197427088Sminshall /*VARARGS*/ 197527088Sminshall quit() 197627088Sminshall { 197727261Sminshall (void) call(bye, "bye", 0); 197827088Sminshall exit(0); 197927261Sminshall /*NOTREACHED*/ 198027088Sminshall } 198127088Sminshall 198227088Sminshall /* 198327088Sminshall * Print status about the connection. 198427088Sminshall */ 198527186Sminshall /*ARGSUSED*/ 198627178Sminshall status(argc, argv) 198727178Sminshall int argc; 198827178Sminshall char *argv[]; 198927088Sminshall { 199027178Sminshall if (connected) { 199127178Sminshall printf("Connected to %s.\n", hostname); 199227178Sminshall if (argc < 2) { 199327178Sminshall printf("Operating in %s.\n", modedescriptions[getconnmode()]); 199427261Sminshall if (localchars) { 199527178Sminshall printf("Catching signals locally.\n"); 199627178Sminshall } 199727110Sminshall } 199827178Sminshall } else { 199927178Sminshall printf("No connection.\n"); 200027178Sminshall } 200127178Sminshall printf("Escape character is '%s'.\n", control(escape)); 200227178Sminshall fflush(stdout); 200327261Sminshall return 1; 200427088Sminshall } 200527088Sminshall 200627088Sminshall tn(argc, argv) 200727088Sminshall int argc; 200827088Sminshall char *argv[]; 200927088Sminshall { 201027088Sminshall register struct hostent *host = 0; 201127088Sminshall 201227088Sminshall if (connected) { 201327088Sminshall printf("?Already connected to %s\n", hostname); 201427261Sminshall return 0; 201527088Sminshall } 201627088Sminshall if (argc < 2) { 201727186Sminshall (void) strcpy(line, "Connect "); 201827088Sminshall printf("(to) "); 201927088Sminshall gets(&line[strlen(line)]); 202027088Sminshall makeargv(); 202127088Sminshall argc = margc; 202227088Sminshall argv = margv; 202327088Sminshall } 202427088Sminshall if (argc > 3) { 202527088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 202627261Sminshall return 0; 202727088Sminshall } 202827088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 202927088Sminshall if (sin.sin_addr.s_addr != -1) { 203027088Sminshall sin.sin_family = AF_INET; 203127186Sminshall (void) strcpy(hnamebuf, argv[1]); 203227088Sminshall hostname = hnamebuf; 203327088Sminshall } else { 203427088Sminshall host = gethostbyname(argv[1]); 203527088Sminshall if (host) { 203627088Sminshall sin.sin_family = host->h_addrtype; 2037*27676Sminshall #ifndef NOT43 203827088Sminshall bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 203927088Sminshall host->h_length); 2040*27676Sminshall #else NOT43 2041*27676Sminshall bcopy(host->h_addr, (caddr_t)&sin.sin_addr, 2042*27676Sminshall host->h_length); 2043*27676Sminshall #endif NOT43 204427088Sminshall hostname = host->h_name; 204527088Sminshall } else { 204627088Sminshall printf("%s: unknown host\n", argv[1]); 204727261Sminshall return 0; 204827088Sminshall } 204927088Sminshall } 205027088Sminshall sin.sin_port = sp->s_port; 205127088Sminshall if (argc == 3) { 205227088Sminshall sin.sin_port = atoi(argv[2]); 205327186Sminshall if (sin.sin_port == 0) { 205427088Sminshall sp = getservbyname(argv[2], "tcp"); 205527088Sminshall if (sp) 205627088Sminshall sin.sin_port = sp->s_port; 205727088Sminshall else { 205827088Sminshall printf("%s: bad port number\n", argv[2]); 205927261Sminshall return 0; 206027088Sminshall } 206127088Sminshall } else { 206227088Sminshall sin.sin_port = atoi(argv[2]); 206327088Sminshall sin.sin_port = htons(sin.sin_port); 206427088Sminshall } 206527088Sminshall telnetport = 0; 206627110Sminshall } else { 206727110Sminshall telnetport = 1; 206827088Sminshall } 206927088Sminshall signal(SIGINT, intr); 207027110Sminshall signal(SIGQUIT, intr2); 207127088Sminshall signal(SIGPIPE, deadpeer); 207227088Sminshall printf("Trying...\n"); 207327088Sminshall do { 207427088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 207527088Sminshall if (net < 0) { 207627088Sminshall perror("telnet: socket"); 207727261Sminshall return 0; 207827088Sminshall } 2079*27676Sminshall #ifndef NOT43 208027186Sminshall if (debug && 208127186Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, 2082*27676Sminshall (char *)&debug, sizeof(debug)) < 0) 2083*27676Sminshall #else NOT43 2084*27676Sminshall if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 2085*27676Sminshall #endif NOT43 208627088Sminshall perror("setsockopt (SO_DEBUG)"); 2087*27676Sminshall 208827186Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 2089*27676Sminshall #ifndef NOT43 209027088Sminshall if (host && host->h_addr_list[1]) { 209127088Sminshall int oerrno = errno; 209227088Sminshall 209327088Sminshall fprintf(stderr, 209427088Sminshall "telnet: connect to address %s: ", 209527088Sminshall inet_ntoa(sin.sin_addr)); 209627088Sminshall errno = oerrno; 209727186Sminshall perror((char *)0); 209827088Sminshall host->h_addr_list++; 209927088Sminshall bcopy(host->h_addr_list[0], 210027088Sminshall (caddr_t)&sin.sin_addr, host->h_length); 210127088Sminshall fprintf(stderr, "Trying %s...\n", 210227088Sminshall inet_ntoa(sin.sin_addr)); 210327088Sminshall (void) close(net); 210427088Sminshall continue; 210527088Sminshall } 2106*27676Sminshall #endif NOT43 210727088Sminshall perror("telnet: connect"); 210827088Sminshall signal(SIGINT, SIG_DFL); 210927261Sminshall signal(SIGQUIT, SIG_DFL); 211027261Sminshall return 0; 211127088Sminshall } 211227088Sminshall connected++; 211327088Sminshall } while (connected == 0); 211427178Sminshall call(status, "status", "notmuch", 0); 211527088Sminshall if (setjmp(peerdied) == 0) 211627088Sminshall telnet(); 211727088Sminshall fprintf(stderr, "Connection closed by foreign host.\n"); 211827088Sminshall exit(1); 211927261Sminshall /*NOTREACHED*/ 212027088Sminshall } 212127088Sminshall 212227088Sminshall 212327088Sminshall #define HELPINDENT (sizeof ("connect")) 212427088Sminshall 212527088Sminshall char openhelp[] = "connect to a site"; 212627088Sminshall char closehelp[] = "close current connection"; 212727088Sminshall char quithelp[] = "exit telnet"; 212827088Sminshall char zhelp[] = "suspend telnet"; 212927088Sminshall char statushelp[] = "print status information"; 213027088Sminshall char helphelp[] = "print help information"; 213127110Sminshall char sendhelp[] = "transmit special characters ('send ?' for more)"; 213227178Sminshall char sethelp[] = "set operating parameters ('set ?' for more)"; 213327178Sminshall char togglestring[] ="toggle operating parameters ('toggle ?' for more)"; 213427178Sminshall char displayhelp[] = "display operating parameters"; 213527178Sminshall char modehelp[] = 213627178Sminshall "try to enter line-by-line or character-at-a-time mode"; 213727088Sminshall 213827088Sminshall int help(); 213927088Sminshall 214027088Sminshall struct cmd cmdtab[] = { 214127261Sminshall { "close", closehelp, bye, 1, 1 }, 214227261Sminshall { "display", displayhelp, display, 1, 0 }, 214327261Sminshall { "mode", modehelp, modecmd, 1, 1 }, 214427110Sminshall { "open", openhelp, tn, 1, 0 }, 214527110Sminshall { "quit", quithelp, quit, 1, 0 }, 214627110Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 214727178Sminshall { "set", sethelp, setcmd, 1, 0 }, 214827261Sminshall { "status", statushelp, status, 1, 0 }, 214927110Sminshall { "toggle", togglestring, toggle, 1, 0 }, 215027261Sminshall { "z", zhelp, suspend, 1, 0 }, 215127110Sminshall { "?", helphelp, help, 1, 0 }, 215227261Sminshall 0 215327261Sminshall }; 215427261Sminshall 215527261Sminshall char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 215627261Sminshall char escapehelp[] = "deprecated command -- use 'set escape' instead"; 215727261Sminshall 215827261Sminshall struct cmd cmdtab2[] = { 215927110Sminshall { "help", helphelp, help, 0, 0 }, 216027261Sminshall { "escape", escapehelp, setescape, 1, 0 }, 216127261Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 216227088Sminshall 0 216327088Sminshall }; 216427088Sminshall 216527088Sminshall /* 216627088Sminshall * Help command. 216727088Sminshall */ 216827088Sminshall help(argc, argv) 216927088Sminshall int argc; 217027088Sminshall char *argv[]; 217127088Sminshall { 217227088Sminshall register struct cmd *c; 217327088Sminshall 217427088Sminshall if (argc == 1) { 217527088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 217627088Sminshall for (c = cmdtab; c->name; c++) 217727088Sminshall if (c->dohelp) { 217827088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 217927088Sminshall c->help); 218027088Sminshall } 218127261Sminshall return 0; 218227088Sminshall } 218327088Sminshall while (--argc > 0) { 218427088Sminshall register char *arg; 218527088Sminshall arg = *++argv; 218627088Sminshall c = getcmd(arg); 218727186Sminshall if (c == Ambiguous(struct cmd *)) 218827088Sminshall printf("?Ambiguous help command %s\n", arg); 218927088Sminshall else if (c == (struct cmd *)0) 219027088Sminshall printf("?Invalid help command %s\n", arg); 219127088Sminshall else 219227088Sminshall printf("%s\n", c->help); 219327088Sminshall } 219427261Sminshall return 0; 219527088Sminshall } 219627088Sminshall /* 219727088Sminshall * Call routine with argc, argv set from args (terminated by 0). 219827088Sminshall * VARARGS2 219927088Sminshall */ 220027088Sminshall call(routine, args) 220127088Sminshall int (*routine)(); 220227186Sminshall char *args; 220327088Sminshall { 220427186Sminshall register char **argp; 220527088Sminshall register int argc; 220627088Sminshall 220727088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 220827088Sminshall ; 220927261Sminshall return (*routine)(argc, &args); 221027088Sminshall } 221127088Sminshall 221227088Sminshall makeargv() 221327088Sminshall { 221427088Sminshall register char *cp; 221527088Sminshall register char **argp = margv; 221627088Sminshall 221727088Sminshall margc = 0; 221827088Sminshall for (cp = line; *cp;) { 221927088Sminshall while (isspace(*cp)) 222027088Sminshall cp++; 222127088Sminshall if (*cp == '\0') 222227088Sminshall break; 222327088Sminshall *argp++ = cp; 222427088Sminshall margc += 1; 222527088Sminshall while (*cp != '\0' && !isspace(*cp)) 222627088Sminshall cp++; 222727088Sminshall if (*cp == '\0') 222827088Sminshall break; 222927088Sminshall *cp++ = '\0'; 223027088Sminshall } 223127088Sminshall *argp++ = 0; 223227088Sminshall } 223327088Sminshall 223427088Sminshall char ** 223527088Sminshall getnextcmd(name) 223627088Sminshall char *name; 223727088Sminshall { 223827088Sminshall struct cmd *c = (struct cmd *) name; 223927088Sminshall 224027088Sminshall return (char **) (c+1); 224127088Sminshall } 224227088Sminshall 224327088Sminshall struct cmd * 224427088Sminshall getcmd(name) 224527088Sminshall char *name; 224627088Sminshall { 224727261Sminshall struct cmd *cm; 224827261Sminshall 224927261Sminshall if (cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) { 225027261Sminshall return cm; 225127261Sminshall } else { 225227261Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 225327261Sminshall } 225427088Sminshall } 225527088Sminshall 225627088Sminshall command(top) 225727088Sminshall int top; 225827088Sminshall { 225927088Sminshall register struct cmd *c; 226027088Sminshall 226127110Sminshall setcommandmode(); 226227261Sminshall if (!top) { 226327088Sminshall putchar('\n'); 226427261Sminshall } else { 226527088Sminshall signal(SIGINT, SIG_DFL); 226627261Sminshall signal(SIGQUIT, SIG_DFL); 226727261Sminshall } 226827088Sminshall for (;;) { 226927088Sminshall printf("%s> ", prompt); 227027088Sminshall if (gets(line) == 0) { 227127088Sminshall if (feof(stdin)) 227227088Sminshall quit(); 227327088Sminshall break; 227427088Sminshall } 227527088Sminshall if (line[0] == 0) 227627088Sminshall break; 227727088Sminshall makeargv(); 227827088Sminshall c = getcmd(margv[0]); 227927186Sminshall if (c == Ambiguous(struct cmd *)) { 228027088Sminshall printf("?Ambiguous command\n"); 228127088Sminshall continue; 228227088Sminshall } 228327088Sminshall if (c == 0) { 228427088Sminshall printf("?Invalid command\n"); 228527088Sminshall continue; 228627088Sminshall } 228727088Sminshall if (c->needconnect && !connected) { 228827088Sminshall printf("?Need to be connected first.\n"); 228927088Sminshall continue; 229027088Sminshall } 229127261Sminshall if ((*c->handler)(margc, margv)) { 229227088Sminshall break; 229327261Sminshall } 229427088Sminshall } 229527088Sminshall if (!top) { 229627110Sminshall if (!connected) { 229727088Sminshall longjmp(toplevel, 1); 229827110Sminshall /*NOTREACHED*/ 229927110Sminshall } 230027110Sminshall setconnmode(); 230127088Sminshall } 230227088Sminshall } 230327186Sminshall 230427186Sminshall /* 230527186Sminshall * main. Parse arguments, invoke the protocol or command parser. 230627186Sminshall */ 230727186Sminshall 230827186Sminshall 230927186Sminshall main(argc, argv) 231027186Sminshall int argc; 231127186Sminshall char *argv[]; 231227186Sminshall { 231327186Sminshall sp = getservbyname("telnet", "tcp"); 231427186Sminshall if (sp == 0) { 231527186Sminshall fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 231627186Sminshall exit(1); 231727186Sminshall } 231827186Sminshall NetTrace = stdout; 231927186Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 232027186Sminshall ioctl(0, TIOCGETC, (char *)&otc); 232127186Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 232227228Sminshall #if defined(LNOFLSH) 232327228Sminshall ioctl(0, TIOCLGET, (char *)&autoflush); 232427261Sminshall autoflush = !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ 232527261Sminshall #else /* LNOFLSH */ 232627261Sminshall autoflush = 1; 232727228Sminshall #endif /* LNOFLSH */ 232827186Sminshall ntc = otc; 232927228Sminshall nltc = oltc; 233027186Sminshall nttyb = ottyb; 233127186Sminshall setbuf(stdin, (char *)0); 233227186Sminshall setbuf(stdout, (char *)0); 233327186Sminshall prompt = argv[0]; 233427186Sminshall if (argc > 1 && !strcmp(argv[1], "-d")) { 233527186Sminshall debug = 1; 233627186Sminshall argv++; 233727186Sminshall argc--; 233827186Sminshall } 233927186Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 234027186Sminshall argv++; 234127186Sminshall argc--; 234227186Sminshall if (argc > 1) { /* get file name */ 234327186Sminshall NetTrace = fopen(argv[1], "w"); 234427186Sminshall argv++; 234527186Sminshall argc--; 234627186Sminshall if (NetTrace == NULL) { 234727186Sminshall NetTrace = stdout; 234827186Sminshall } 234927186Sminshall } 235027186Sminshall } 235127186Sminshall if (argc != 1) { 235227186Sminshall if (setjmp(toplevel) != 0) 235327186Sminshall exit(0); 235427186Sminshall tn(argc, argv); 235527186Sminshall } 235627186Sminshall setjmp(toplevel); 235727186Sminshall for (;;) 235827186Sminshall command(1); 235927186Sminshall } 2360