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*27261Sminshall static char sccsid[] = "@(#)telnet.c 5.12 (Berkeley) 04/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 4127178Sminshall /* 4227178Sminshall * The following is defined just in case someone should want to run 4327178Sminshall * this telnet on a 4.2 system. 4427178Sminshall * 4527178Sminshall * This has never been tested, so good luck... 4627178Sminshall */ 4727178Sminshall #ifndef FD_SETSIZE 4827178Sminshall 4927178Sminshall typedef long fd_set; 5027178Sminshall 5127178Sminshall #define FD_SET(n, p) (*(p) |= (1<<(n))) 5227178Sminshall #define FD_CLR(n, p) (*(p) &= ~(1<<(n))) 5327178Sminshall #define FD_ISSET(n, p) (*(p) & (1<<(n))) 5427178Sminshall #define FD_ZERO(p) (*(p) = 0) 5527178Sminshall 5627178Sminshall #endif 5727178Sminshall 5827228Sminshall #define strip(x) ((x)&0x7f) 596000Sroot 6027228Sminshall char ttyobuf[2*BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; 6127228Sminshall #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } } 6227228Sminshall #define TTYLOC() (tfrontp) 6327228Sminshall #define TTYMAX() (ttyobuf+sizeof ttyobuf-1) 6427228Sminshall #define TTYMIN() (netobuf) 6527228Sminshall #define TTYBYTES() (tfrontp-tbackp) 6627228Sminshall #define TTYROOM() (TTYMAX()-TTYLOC()+1) 6727088Sminshall 6827228Sminshall char netobuf[2*BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 6927088Sminshall #define NETADD(c) { *nfrontp++ = c; } 7027088Sminshall #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } 7127088Sminshall #define NETLOC() (nfrontp) 7227228Sminshall #define NETMAX() (netobuf+sizeof netobuf-1) 7327228Sminshall #define NETBYTES() (nfrontp-nbackp) 7427228Sminshall #define NETROOM() (NETMAX()-NETLOC()+1) 7527088Sminshall char *neturg = 0; /* one past last byte of urgent data */ 766000Sroot 776000Sroot char hisopts[256]; 786000Sroot char myopts[256]; 796000Sroot 806000Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 816000Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 826000Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 836000Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 846000Sroot 8527088Sminshall struct cmd { 8627088Sminshall char *name; /* command name */ 8727088Sminshall char *help; /* help string */ 8827088Sminshall int (*handler)(); /* routine which executes command */ 8927088Sminshall int dohelp; /* Should we give general help information? */ 9027088Sminshall int needconnect; /* Do we need to be connected to execute? */ 9127088Sminshall }; 9227088Sminshall 936000Sroot int connected; 946000Sroot int net; 9527088Sminshall int tout; 969972Ssam int showoptions = 0; 9710339Ssam int debug = 0; 989972Ssam int crmod = 0; 9927088Sminshall int netdata = 0; 10027021Sminshall static FILE *NetTrace; 10125289Skarels int telnetport = 1; 10227088Sminshall 10327088Sminshall 1046000Sroot char *prompt; 1059972Ssam char escape = CTRL(]); 10627110Sminshall char echoc = CTRL(E); 1076000Sroot 10827186Sminshall int SYNCHing = 0; /* we are in TELNET SYNCH mode */ 10927186Sminshall int flushout = 0; /* flush output */ 11027228Sminshall int autoflush = 0; /* flush output when interrupting? */ 11127186Sminshall int autosynch = 0; /* send interrupt characters with SYNCH? */ 112*27261Sminshall int localchars = 0; /* we recognize interrupt/quit */ 113*27261Sminshall int donelclchars = 0; /* the user has set "localchars" */ 11427186Sminshall int dontlecho = 0; /* do we suppress local echoing right now? */ 11527186Sminshall 1166000Sroot char line[200]; 1176000Sroot int margc; 1186000Sroot char *margv[20]; 1196000Sroot 1206000Sroot jmp_buf toplevel; 1216000Sroot jmp_buf peerdied; 1226000Sroot 1236000Sroot extern int errno; 1246000Sroot 1256000Sroot 1269972Ssam struct sockaddr_in sin; 1276000Sroot 1286000Sroot struct cmd *getcmd(); 1298345Ssam struct servent *sp; 1306000Sroot 13127110Sminshall struct tchars otc, ntc; 13227228Sminshall struct ltchars oltc, nltc; 13327110Sminshall struct sgttyb ottyb, nttyb; 13427110Sminshall int globalmode = 0; 13527110Sminshall int flushline = 1; 1368378Ssam 13727110Sminshall char *hostname; 13827110Sminshall char hnamebuf[32]; 13927110Sminshall 14027110Sminshall /* 14127110Sminshall * The following are some clocks used to decide how to interpret 14227178Sminshall * the relationship between various variables. 14327110Sminshall */ 14427110Sminshall 14527110Sminshall struct { 14627110Sminshall int 14727110Sminshall system, /* what the current time is */ 14827110Sminshall echotoggle, /* last time user entered echo character */ 14927178Sminshall modenegotiated, /* last time operating mode negotiated */ 15027178Sminshall didnetreceive, /* last time we read data from network */ 15127178Sminshall gotDM; /* when did we last see a data mark */ 15227186Sminshall } clocks; 15327110Sminshall 15427186Sminshall #define settimer(x) clocks.x = clocks.system++ 15527110Sminshall 15627110Sminshall /* 15727110Sminshall * Various utility routines. 15827110Sminshall */ 1596000Sroot 16027186Sminshall char *ambiguous; /* special return value */ 16127186Sminshall #define Ambiguous(t) ((t)&ambiguous) 16227186Sminshall 16327186Sminshall 16427088Sminshall char ** 16527088Sminshall genget(name, table, next) 16627088Sminshall char *name; /* name to match */ 16727088Sminshall char **table; /* name entry in table */ 16827088Sminshall char **(*next)(); /* routine to return next entry in table */ 1696000Sroot { 17027088Sminshall register char *p, *q; 17127088Sminshall register char **c, **found; 17227088Sminshall register int nmatches, longest; 1736000Sroot 17427088Sminshall longest = 0; 17527088Sminshall nmatches = 0; 17627088Sminshall found = 0; 17727088Sminshall for (c = table; p = *c; c = (*next)(c)) { 17827088Sminshall for (q = name; *q == *p++; q++) 17927088Sminshall if (*q == 0) /* exact match? */ 18027088Sminshall return (c); 18127088Sminshall if (!*q) { /* the name was a prefix */ 18227088Sminshall if (q - name > longest) { 18327088Sminshall longest = q - name; 18427088Sminshall nmatches = 1; 18527088Sminshall found = c; 18627088Sminshall } else if (q - name == longest) 18727088Sminshall nmatches++; 1888377Ssam } 1896000Sroot } 19027088Sminshall if (nmatches > 1) 19127186Sminshall return Ambiguous(char **); 19227088Sminshall return (found); 1936000Sroot } 1946000Sroot 19527110Sminshall /* 19627110Sminshall * Make a character string into a number. 19727110Sminshall * 19827186Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 19927110Sminshall */ 2006000Sroot 20127110Sminshall special(s) 20227110Sminshall register char *s; 20327110Sminshall { 20427110Sminshall register char c; 20527110Sminshall char b; 20627110Sminshall 20727110Sminshall switch (*s) { 20827110Sminshall case '^': 20927110Sminshall b = *++s; 21027110Sminshall if (b == '?') { 21127228Sminshall c = b | 0x40; /* DEL */ 21227110Sminshall } else { 21327110Sminshall c = b & 0x1f; 21427110Sminshall } 21527110Sminshall break; 21627110Sminshall default: 21727110Sminshall c = *s; 21827110Sminshall break; 21927110Sminshall } 22027110Sminshall return c; 22127110Sminshall } 22227186Sminshall 22327186Sminshall /* 22427186Sminshall * Construct a control character sequence 22527186Sminshall * for a special character. 22627186Sminshall */ 22727186Sminshall char * 22827186Sminshall control(c) 22927186Sminshall register int c; 23027186Sminshall { 23127186Sminshall static char buf[3]; 23227186Sminshall 23327228Sminshall if (c == 0x7f) 23427186Sminshall return ("^?"); 23527186Sminshall if (c == '\377') { 23627186Sminshall return "off"; 23727186Sminshall } 23827186Sminshall if (c >= 0x20) { 23927186Sminshall buf[0] = c; 24027186Sminshall buf[1] = 0; 24127186Sminshall } else { 24227186Sminshall buf[0] = '^'; 24327186Sminshall buf[1] = '@'+c; 24427186Sminshall buf[2] = 0; 24527186Sminshall } 24627186Sminshall return (buf); 24727186Sminshall } 24827110Sminshall 24927110Sminshall /* 25027186Sminshall * Check to see if any out-of-band data exists on a socket (for 25127186Sminshall * Telnet "synch" processing). 25227186Sminshall */ 25327186Sminshall 25427186Sminshall int 25527186Sminshall stilloob(s) 25627186Sminshall int s; /* socket number */ 25727186Sminshall { 25827186Sminshall static struct timeval timeout = { 0 }; 25927186Sminshall fd_set excepts; 26027186Sminshall int value; 26127186Sminshall 26227186Sminshall do { 26327186Sminshall FD_ZERO(&excepts); 26427186Sminshall FD_SET(s, &excepts); 26527186Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 26627186Sminshall } while ((value == -1) && (errno = EINTR)); 26727186Sminshall 26827186Sminshall if (value < 0) { 26927186Sminshall perror("select"); 27027186Sminshall quit(); 27127186Sminshall } 27227186Sminshall if (FD_ISSET(s, &excepts)) { 27327186Sminshall return 1; 27427186Sminshall } else { 27527186Sminshall return 0; 27627186Sminshall } 27727186Sminshall } 27827186Sminshall 27927186Sminshall 28027186Sminshall /* 28127186Sminshall * netflush 28227186Sminshall * Send as much data as possible to the network, 28327186Sminshall * handling requests for urgent data. 28427186Sminshall */ 28527186Sminshall 28627186Sminshall 28727186Sminshall netflush(fd) 28827186Sminshall { 28927186Sminshall int n; 29027186Sminshall 29127186Sminshall if ((n = nfrontp - nbackp) > 0) { 29227186Sminshall if (!neturg) { 29327186Sminshall n = write(fd, nbackp, n); /* normal write */ 29427186Sminshall } else { 29527186Sminshall n = neturg - nbackp; 29627186Sminshall /* 29727186Sminshall * In 4.2 (and 4.3) systems, there is some question about 29827186Sminshall * what byte in a sendOOB operation is the "OOB" data. 29927186Sminshall * To make ourselves compatible, we only send ONE byte 30027186Sminshall * out of band, the one WE THINK should be OOB (though 30127186Sminshall * we really have more the TCP philosophy of urgent data 30227186Sminshall * rather than the Unix philosophy of OOB data). 30327186Sminshall */ 30427186Sminshall if (n > 1) { 30527186Sminshall n = send(fd, nbackp, n-1, 0); /* send URGENT all by itself */ 30627186Sminshall } else { 30727186Sminshall n = send(fd, nbackp, n, MSG_OOB); /* URGENT data */ 30827186Sminshall } 30927186Sminshall } 31027186Sminshall } 31127186Sminshall if (n < 0) { 31227186Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 31327186Sminshall setcommandmode(); 31427186Sminshall perror(hostname); 31527186Sminshall close(fd); 31627186Sminshall neturg = 0; 31727186Sminshall longjmp(peerdied, -1); 31827186Sminshall /*NOTREACHED*/ 31927186Sminshall } 32027186Sminshall n = 0; 32127186Sminshall } 32227186Sminshall if (netdata && n) { 32327186Sminshall Dump('>', nbackp, n); 32427186Sminshall } 32527186Sminshall nbackp += n; 32627186Sminshall if (nbackp >= neturg) { 32727186Sminshall neturg = 0; 32827186Sminshall } 32927186Sminshall if (nbackp == nfrontp) { 33027186Sminshall nbackp = nfrontp = netobuf; 33127186Sminshall } 33227186Sminshall } 333*27261Sminshall 334*27261Sminshall /* 335*27261Sminshall * nextitem() 336*27261Sminshall * 337*27261Sminshall * Return the address of the next "item" in the TELNET data 338*27261Sminshall * stream. This will be the address of the next character if 339*27261Sminshall * the current address is a user data character, or it will 340*27261Sminshall * be the address of the character following the TELNET command 341*27261Sminshall * if the current address is a TELNET IAC ("I Am a Command") 342*27261Sminshall * character. 343*27261Sminshall */ 34427186Sminshall 345*27261Sminshall char * 346*27261Sminshall nextitem(current) 347*27261Sminshall char *current; 348*27261Sminshall { 349*27261Sminshall if ((*current&0xff) != IAC) { 350*27261Sminshall return current+1; 351*27261Sminshall } 352*27261Sminshall switch (*(current+1)&0xff) { 353*27261Sminshall case DO: 354*27261Sminshall case DONT: 355*27261Sminshall case WILL: 356*27261Sminshall case WONT: 357*27261Sminshall return current+3; 358*27261Sminshall case SB: /* loop forever looking for the SE */ 359*27261Sminshall { 360*27261Sminshall register char *look = current+2; 361*27261Sminshall 362*27261Sminshall for (;;) { 363*27261Sminshall if ((*look++&0xff) == IAC) { 364*27261Sminshall if ((*look++&0xff) == SE) { 365*27261Sminshall return look; 366*27261Sminshall } 367*27261Sminshall } 368*27261Sminshall } 369*27261Sminshall } 370*27261Sminshall default: 371*27261Sminshall return current+2; 372*27261Sminshall } 373*27261Sminshall } 37427186Sminshall /* 375*27261Sminshall * netclear() 376*27261Sminshall * 377*27261Sminshall * We are about to do a TELNET SYNCH operation. Clear 378*27261Sminshall * the path to the network. 379*27261Sminshall * 380*27261Sminshall * Things are a bit tricky since we may have sent the first 381*27261Sminshall * byte or so of a previous TELNET command into the network. 382*27261Sminshall * So, we have to scan the network buffer from the beginning 383*27261Sminshall * until we are up to where we want to be. 384*27261Sminshall * 385*27261Sminshall * A side effect of what we do, just to keep things 386*27261Sminshall * simple, is to clear the urgent data pointer. The principal 387*27261Sminshall * caller should be setting the urgent data pointer AFTER calling 388*27261Sminshall * us in any case. 389*27261Sminshall */ 390*27261Sminshall 391*27261Sminshall netclear() 392*27261Sminshall { 393*27261Sminshall register char *thisitem, *next; 394*27261Sminshall char *good; 395*27261Sminshall #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 396*27261Sminshall ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 397*27261Sminshall 398*27261Sminshall thisitem = netobuf; 399*27261Sminshall 400*27261Sminshall while ((next = nextitem(thisitem)) <= nbackp) { 401*27261Sminshall thisitem = next; 402*27261Sminshall } 403*27261Sminshall 404*27261Sminshall /* Now, thisitem is first before/at boundary. */ 405*27261Sminshall 406*27261Sminshall good = netobuf; /* where the good bytes go */ 407*27261Sminshall 408*27261Sminshall while (nfrontp > thisitem) { 409*27261Sminshall if (wewant(thisitem)) { 410*27261Sminshall int length; 411*27261Sminshall 412*27261Sminshall next = thisitem; 413*27261Sminshall do { 414*27261Sminshall next = nextitem(next); 415*27261Sminshall } while (wewant(next) && (nfrontp > next)); 416*27261Sminshall length = next-thisitem; 417*27261Sminshall bcopy(thisitem, good, length); 418*27261Sminshall good += length; 419*27261Sminshall thisitem = next; 420*27261Sminshall } else { 421*27261Sminshall thisitem = nextitem(thisitem); 422*27261Sminshall } 423*27261Sminshall } 424*27261Sminshall 425*27261Sminshall nbackp = netobuf; 426*27261Sminshall nfrontp = good; /* next byte to be sent */ 427*27261Sminshall neturg = 0; 428*27261Sminshall } 429*27261Sminshall 430*27261Sminshall /* 43127186Sminshall * Send as much data as possible to the terminal. 43227186Sminshall */ 43327186Sminshall 43427186Sminshall 43527186Sminshall ttyflush() 43627186Sminshall { 43727186Sminshall int n; 43827186Sminshall 43927186Sminshall if ((n = tfrontp - tbackp) > 0) { 44027228Sminshall if (!(SYNCHing||flushout)) { 44127186Sminshall n = write(tout, tbackp, n); 44227186Sminshall } else { 44327186Sminshall ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 44427228Sminshall /* we leave 'n' alone! */ 44527186Sminshall } 44627186Sminshall } 44727186Sminshall if (n < 0) { 44827186Sminshall return; 44927186Sminshall } 45027186Sminshall tbackp += n; 45127186Sminshall if (tbackp == tfrontp) { 45227186Sminshall tbackp = tfrontp = ttyobuf; 45327186Sminshall } 45427186Sminshall } 45527186Sminshall 45627186Sminshall /* 45727110Sminshall * Various signal handling routines. 45827110Sminshall */ 45927110Sminshall 46027110Sminshall deadpeer() 46127110Sminshall { 46227110Sminshall setcommandmode(); 46327110Sminshall longjmp(peerdied, -1); 46427110Sminshall } 46527110Sminshall 46627110Sminshall intr() 46727110Sminshall { 468*27261Sminshall if (localchars) { 46927110Sminshall intp(); 47027110Sminshall return; 47127110Sminshall } 47227110Sminshall setcommandmode(); 47327110Sminshall longjmp(toplevel, -1); 47427110Sminshall } 47527110Sminshall 47627110Sminshall intr2() 47727110Sminshall { 478*27261Sminshall if (localchars) { 47927110Sminshall sendbrk(); 48027110Sminshall return; 48127110Sminshall } 48227110Sminshall } 48327110Sminshall 48427110Sminshall doescape() 48527110Sminshall { 48627110Sminshall command(0); 48727110Sminshall } 48827110Sminshall 48927110Sminshall /* 49027186Sminshall * The following are routines used to print out debugging information. 49127186Sminshall */ 49227186Sminshall 49327186Sminshall 49427186Sminshall static 49527186Sminshall Dump(direction, buffer, length) 49627186Sminshall char direction; 49727186Sminshall char *buffer; 49827186Sminshall int length; 49927186Sminshall { 50027186Sminshall # define BYTES_PER_LINE 32 50127186Sminshall # define min(x,y) ((x<y)? x:y) 50227186Sminshall char *pThis; 50327186Sminshall int offset; 50427186Sminshall 50527186Sminshall offset = 0; 50627186Sminshall 50727186Sminshall while (length) { 50827186Sminshall /* print one line */ 50927186Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 51027186Sminshall pThis = buffer; 51127186Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 51227186Sminshall while (pThis < buffer) { 51327186Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 51427186Sminshall pThis++; 51527186Sminshall } 51627186Sminshall fprintf(NetTrace, "\n"); 51727186Sminshall length -= BYTES_PER_LINE; 51827186Sminshall offset += BYTES_PER_LINE; 51927186Sminshall if (length < 0) { 52027186Sminshall return; 52127186Sminshall } 52227186Sminshall /* find next unique line */ 52327186Sminshall } 52427186Sminshall } 52527186Sminshall 52627186Sminshall 52727186Sminshall /*VARARGS*/ 52827186Sminshall printoption(direction, fmt, option, what) 52927186Sminshall char *direction, *fmt; 53027186Sminshall int option, what; 53127186Sminshall { 53227186Sminshall if (!showoptions) 53327186Sminshall return; 53427186Sminshall printf("%s ", direction); 53527186Sminshall if (fmt == doopt) 53627186Sminshall fmt = "do"; 53727186Sminshall else if (fmt == dont) 53827186Sminshall fmt = "dont"; 53927186Sminshall else if (fmt == will) 54027186Sminshall fmt = "will"; 54127186Sminshall else if (fmt == wont) 54227186Sminshall fmt = "wont"; 54327186Sminshall else 54427186Sminshall fmt = "???"; 54527186Sminshall if (option < TELOPT_SUPDUP) 54627186Sminshall printf("%s %s", fmt, telopts[option]); 54727186Sminshall else 54827186Sminshall printf("%s %d", fmt, option); 54927186Sminshall if (*direction == '<') { 55027186Sminshall printf("\r\n"); 55127186Sminshall return; 55227186Sminshall } 55327186Sminshall printf(" (%s)\r\n", what ? "reply" : "don't reply"); 55427186Sminshall } 55527186Sminshall 55627186Sminshall /* 55727110Sminshall * Mode - set up terminal to a specific mode. 55827110Sminshall */ 55927110Sminshall 5609972Ssam 5616000Sroot mode(f) 5626000Sroot register int f; 5636000Sroot { 5648378Ssam static int prevmode = 0; 56513076Ssam struct tchars *tc; 56613076Ssam struct ltchars *ltc; 56713076Ssam struct sgttyb sb; 56813076Ssam int onoff, old; 56927228Sminshall struct tchars notc2; 57027228Sminshall struct ltchars noltc2; 57127228Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 57227228Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 5736000Sroot 57427110Sminshall globalmode = f; 5758378Ssam if (prevmode == f) 57627186Sminshall return; 5778378Ssam old = prevmode; 5788378Ssam prevmode = f; 57927110Sminshall sb = nttyb; 5806000Sroot switch (f) { 5818378Ssam 5826000Sroot case 0: 5836000Sroot onoff = 0; 5849972Ssam tc = &otc; 58513076Ssam ltc = &oltc; 5866000Sroot break; 5876000Sroot 58827110Sminshall case 1: /* remote character processing, remote echo */ 58927110Sminshall case 2: /* remote character processing, local echo */ 59013076Ssam sb.sg_flags |= CBREAK; 5918378Ssam if (f == 1) 59213076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 5938378Ssam else 59413076Ssam sb.sg_flags |= ECHO|CRMOD; 59513076Ssam sb.sg_erase = sb.sg_kill = -1; 5969972Ssam tc = ¬c; 59727110Sminshall /* 59827110Sminshall * If user hasn't specified one way or the other, 59927110Sminshall * then default to not trapping signals. 60027110Sminshall */ 601*27261Sminshall if (!donelclchars) { 602*27261Sminshall localchars = 0; 60327228Sminshall } 604*27261Sminshall if (localchars) { 60527110Sminshall notc2 = notc; 60627110Sminshall notc2.t_intrc = ntc.t_intrc; 60727110Sminshall notc2.t_quitc = ntc.t_quitc; 60827110Sminshall tc = ¬c2; 60927110Sminshall } else 61027110Sminshall tc = ¬c; 61113076Ssam ltc = &noltc; 6126000Sroot onoff = 1; 6139972Ssam break; 61427110Sminshall case 3: /* local character processing, remote echo */ 61527110Sminshall case 4: /* local character processing, local echo */ 61627110Sminshall case 5: /* local character processing, no echo */ 61727110Sminshall sb.sg_flags &= ~CBREAK; 61827110Sminshall sb.sg_flags |= CRMOD; 61927110Sminshall if (f == 4) 62027110Sminshall sb.sg_flags |= ECHO; 62127110Sminshall else 62227110Sminshall sb.sg_flags &= ~ECHO; 62327228Sminshall notc2 = ntc; 62427228Sminshall tc = ¬c2; 62527228Sminshall noltc2 = oltc; 62627228Sminshall ltc = &noltc2; 62727110Sminshall /* 62827110Sminshall * If user hasn't specified one way or the other, 62927110Sminshall * then default to trapping signals. 63027110Sminshall */ 631*27261Sminshall if (!donelclchars) { 632*27261Sminshall localchars = 1; 63327228Sminshall } 634*27261Sminshall if (localchars) { 63527228Sminshall notc2.t_brkc = nltc.t_flushc; 63627228Sminshall noltc2.t_flushc = -1; 63727228Sminshall } else { 63827110Sminshall notc2.t_intrc = notc2.t_quitc = -1; 63927110Sminshall } 64027110Sminshall noltc2.t_suspc = escape; 64127110Sminshall noltc2.t_dsuspc = -1; 64227110Sminshall onoff = 1; 64327110Sminshall break; 6449972Ssam 6459972Ssam default: 6469972Ssam return; 6476000Sroot } 64813076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 64913076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 65013076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 65127186Sminshall ioctl(fileno(stdin), FIONBIO, (char *)&onoff); 65227186Sminshall ioctl(fileno(stdout), FIONBIO, (char *)&onoff); 65327110Sminshall if (f >= 3) 65427110Sminshall signal(SIGTSTP, doescape); 65527110Sminshall else if (old >= 3) { 65627110Sminshall signal(SIGTSTP, SIG_DFL); 65727110Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 65827110Sminshall } 6596000Sroot } 66027186Sminshall 66127110Sminshall /* 66227110Sminshall * These routines decides on what the mode should be (based on the values 66327110Sminshall * of various global variables). 66427110Sminshall */ 66527110Sminshall 66627178Sminshall char *modedescriptions[] = { 66727178Sminshall "telnet command mode", /* 0 */ 66827178Sminshall "character-at-a-time mode", /* 1 */ 66927178Sminshall "character-at-a-time mode (local echo)", /* 2 */ 67027178Sminshall "line-by-line mode (remote echo)", /* 3 */ 67127178Sminshall "line-by-line mode", /* 4 */ 67227178Sminshall "line-by-line mode (local echoing suppressed)", /* 5 */ 67327178Sminshall }; 67427178Sminshall 67527178Sminshall getconnmode() 67627110Sminshall { 67727110Sminshall static char newmode[8] = { 4, 5, 3, 3, 2, 2, 1, 1 }; 67827186Sminshall int modeindex = 0; 67927110Sminshall 68027110Sminshall if (hisopts[TELOPT_ECHO]) { 68127186Sminshall modeindex += 2; 68227110Sminshall } 68327110Sminshall if (hisopts[TELOPT_SGA]) { 68427186Sminshall modeindex += 4; 68527110Sminshall } 68627186Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 68727186Sminshall modeindex += 1; 68827110Sminshall } 68927186Sminshall return newmode[modeindex]; 69027110Sminshall } 69127110Sminshall 69227178Sminshall setconnmode() 69327178Sminshall { 69427178Sminshall mode(getconnmode()); 69527178Sminshall } 69627110Sminshall 69727178Sminshall 69827110Sminshall setcommandmode() 69927110Sminshall { 70027110Sminshall mode(0); 70127110Sminshall } 70227110Sminshall 7036000Sroot char sibuf[BUFSIZ], *sbp; 7046000Sroot char tibuf[BUFSIZ], *tbp; 7056000Sroot int scc, tcc; 7066000Sroot 70727228Sminshall 7086000Sroot /* 7096000Sroot * Select from tty and network... 7106000Sroot */ 71127088Sminshall telnet() 7126000Sroot { 7136000Sroot register int c; 71427088Sminshall int tin = fileno(stdin); 7156000Sroot int on = 1; 716*27261Sminshall fd_set ibits, obits, xbits; 7176000Sroot 71827088Sminshall tout = fileno(stdout); 71927110Sminshall setconnmode(); 72027228Sminshall scc = 0; 72127228Sminshall tcc = 0; 722*27261Sminshall FD_ZERO(&ibits); 723*27261Sminshall FD_ZERO(&obits); 724*27261Sminshall FD_ZERO(&xbits); 725*27261Sminshall 72627186Sminshall ioctl(net, FIONBIO, (char *)&on); 72727228Sminshall #if defined(xxxSO_OOBINLINE) 72827228Sminshall setsockopt(net, SOL_SOCKET, SO_OOBINLINE, on, sizeof on); 72927228Sminshall #endif /* defined(xxxSO_OOBINLINE) */ 73027088Sminshall if (telnetport && !hisopts[TELOPT_SGA]) { 73117922Sralph willoption(TELOPT_SGA); 73227088Sminshall } 7336000Sroot for (;;) { 73427110Sminshall if (scc < 0 && tcc < 0) { 7356000Sroot break; 73627110Sminshall } 73727110Sminshall 73827228Sminshall if (((globalmode < 4) || flushline) && NETBYTES()) { 73927110Sminshall FD_SET(net, &obits); 74027088Sminshall } else { 74127110Sminshall FD_SET(tin, &ibits); 74227088Sminshall } 74327228Sminshall if (TTYBYTES()) { 74427110Sminshall FD_SET(tout, &obits); 74527110Sminshall } else { 74627110Sminshall FD_SET(net, &ibits); 74727110Sminshall } 74827186Sminshall if (!SYNCHing) { 74927110Sminshall FD_SET(net, &xbits); 75027110Sminshall } 75127186Sminshall if ((c = select(16, &ibits, &obits, &xbits, 75227186Sminshall (struct timeval *)0)) < 1) { 75327110Sminshall if (c == -1) { 75427110Sminshall /* 75527110Sminshall * we can get EINTR if we are in line mode, 75627110Sminshall * and the user does an escape (TSTP), or 75727110Sminshall * some other signal generator. 75827110Sminshall */ 75927110Sminshall if (errno == EINTR) { 76027110Sminshall continue; 76127110Sminshall } 76227110Sminshall } 7636000Sroot sleep(5); 7646000Sroot continue; 7656000Sroot } 7666000Sroot 7676000Sroot /* 76827088Sminshall * Any urgent data? 76927088Sminshall */ 77027110Sminshall if (FD_ISSET(net, &xbits)) { 771*27261Sminshall FD_CLR(net, &xbits); 77227186Sminshall SYNCHing = 1; 77327088Sminshall ttyflush(); /* flush already enqueued data */ 77427088Sminshall } 77527088Sminshall 77627088Sminshall /* 7776000Sroot * Something to read from the network... 7786000Sroot */ 77927110Sminshall if (FD_ISSET(net, &ibits)) { 78027228Sminshall int canread; 78127228Sminshall 782*27261Sminshall FD_CLR(net, &ibits); 78327228Sminshall if (scc == 0) { 78427228Sminshall sbp = sibuf; 78527228Sminshall } 78627228Sminshall canread = sibuf + sizeof sibuf - sbp; 78727228Sminshall #if !defined(xxxSO_OOBINLINE) 78827178Sminshall /* 78927178Sminshall * In 4.2 (and some early 4.3) systems, the 79027178Sminshall * OOB indication and data handling in the kernel 79127178Sminshall * is such that if two separate TCP Urgent requests 79227178Sminshall * come in, one byte of TCP data will be overlaid. 79327178Sminshall * This is fatal for Telnet, but we try to live 79427178Sminshall * with it. 79527178Sminshall * 79627178Sminshall * In addition, in 4.2 (and...), a special protocol 79727178Sminshall * is needed to pick up the TCP Urgent data in 79827178Sminshall * the correct sequence. 79927178Sminshall * 80027178Sminshall * What we do is: if we think we are in urgent 80127178Sminshall * mode, we look to see if we are "at the mark". 80227178Sminshall * If we are, we do an OOB receive. If we run 80327178Sminshall * this twice, we will do the OOB receive twice, 80427178Sminshall * but the second will fail, since the second 80527178Sminshall * time we were "at the mark", but there wasn't 80627178Sminshall * any data there (the kernel doesn't reset 80727178Sminshall * "at the mark" until we do a normal read). 80827178Sminshall * Once we've read the OOB data, we go ahead 80927178Sminshall * and do normal reads. 81027178Sminshall * 81127178Sminshall * There is also another problem, which is that 81227178Sminshall * since the OOB byte we read doesn't put us 81327178Sminshall * out of OOB state, and since that byte is most 81427178Sminshall * likely the TELNET DM (data mark), we would 81527186Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 81627178Sminshall * So, clocks to the rescue. If we've "just" 81727178Sminshall * received a DM, then we test for the 81827178Sminshall * presence of OOB data when the receive OOB 81927178Sminshall * fails (and AFTER we did the normal mode read 82027178Sminshall * to clear "at the mark"). 82127178Sminshall */ 82227186Sminshall if (SYNCHing) { 82327178Sminshall int atmark; 82427178Sminshall 82527186Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 82627178Sminshall if (atmark) { 82727228Sminshall c = recv(net, sibuf, canread, MSG_OOB); 82827228Sminshall if ((c == -1) && (errno == EINVAL)) { 82927228Sminshall c = read(net, sibuf, canread); 83027186Sminshall if (clocks.didnetreceive < clocks.gotDM) { 83127186Sminshall SYNCHing = stilloob(net); 83227021Sminshall } 83327178Sminshall } 83427178Sminshall } else { 83527228Sminshall c = read(net, sibuf, canread); 8366000Sroot } 83727178Sminshall } else { 83827228Sminshall c = read(net, sibuf, canread); 83927178Sminshall } 84027178Sminshall settimer(didnetreceive); 84127228Sminshall #else /* !defined(xxxSO_OOBINLINE) */ 84227228Sminshall c = read(net, sbp, canread); 84327228Sminshall #endif /* !defined(xxxSO_OOBINLINE) */ 84427228Sminshall if (c < 0 && errno == EWOULDBLOCK) { 84527228Sminshall c = 0; 84627228Sminshall } else if (c <= 0) { 84727228Sminshall break; 84827178Sminshall } 84927228Sminshall if (netdata) { 85027228Sminshall Dump('<', sbp, c); 85127228Sminshall } 85227228Sminshall scc += c; 8536000Sroot } 8546000Sroot 8556000Sroot /* 8566000Sroot * Something to read from the tty... 8576000Sroot */ 85827110Sminshall if (FD_ISSET(tin, &ibits)) { 859*27261Sminshall FD_CLR(tin, &ibits); 86027228Sminshall if (tcc == 0) { 86127228Sminshall tbp = tibuf; /* nothing left, reset */ 8626000Sroot } 86327228Sminshall c = read(tin, tbp, tibuf+sizeof tibuf - tbp); 86427228Sminshall if (c < 0 && errno == EWOULDBLOCK) { 86527228Sminshall c = 0; 86627228Sminshall } else if (c <= 0) { 86727228Sminshall tcc = c; 86827228Sminshall break; 86927228Sminshall } 87027228Sminshall tcc += c; 8716000Sroot } 8726000Sroot 8736000Sroot while (tcc > 0) { 87427186Sminshall register int sc; 8756000Sroot 87627228Sminshall if (NETROOM() < 2) { 87727110Sminshall flushline = 1; 8786000Sroot break; 87927110Sminshall } 88027186Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 88127186Sminshall if (sc == escape) { 8826000Sroot command(0); 8836000Sroot tcc = 0; 88427110Sminshall flushline = 1; 8856000Sroot break; 886*27261Sminshall } else if ((globalmode >= 4) && (sc == echoc)) { 88727110Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 88827110Sminshall tbp++; 88927110Sminshall tcc--; 89027110Sminshall } else { 89127110Sminshall dontlecho = !dontlecho; 89227110Sminshall settimer(echotoggle); 89327110Sminshall setconnmode(); 89427110Sminshall tcc = 0; 89527110Sminshall flushline = 1; 89627110Sminshall break; 89727110Sminshall } 8986000Sroot } 899*27261Sminshall if (localchars) { 90027186Sminshall if (sc == ntc.t_intrc) { 90127110Sminshall intp(); 90227110Sminshall break; 90327186Sminshall } else if (sc == ntc.t_quitc) { 90427110Sminshall sendbrk(); 90527110Sminshall break; 90627228Sminshall } else if (sc == nltc.t_flushc) { 90727228Sminshall NET2ADD(IAC, AO); 90827228Sminshall if (autoflush) { 90927228Sminshall doflush(); 91027228Sminshall } 91127228Sminshall break; 91227110Sminshall } else if (globalmode > 2) { 91327110Sminshall ; 91427186Sminshall } else if (sc == nttyb.sg_kill) { 91527110Sminshall NET2ADD(IAC, EL); 91627110Sminshall break; 91727186Sminshall } else if (sc == nttyb.sg_erase) { 91827110Sminshall NET2ADD(IAC, EC); 91927110Sminshall break; 92027110Sminshall } 92127110Sminshall } 92217922Sralph switch (c) { 92317922Sralph case '\n': 92427021Sminshall /* 92527021Sminshall * If echoing is happening locally, 92627021Sminshall * then a newline (unix) is CRLF (TELNET). 92727021Sminshall */ 92827088Sminshall if (!hisopts[TELOPT_ECHO]) { 92927088Sminshall NETADD('\r'); 93027088Sminshall } 93127088Sminshall NETADD('\n'); 93227110Sminshall flushline = 1; 93317922Sralph break; 93417922Sralph case '\r': 93527088Sminshall NET2ADD('\r', '\0'); 93627110Sminshall flushline = 1; 93717922Sralph break; 93817922Sralph case IAC: 93927088Sminshall NET2ADD(IAC, IAC); 94027021Sminshall break; 94117922Sralph default: 94227088Sminshall NETADD(c); 94317922Sralph break; 94417922Sralph } 9456000Sroot } 94627110Sminshall if (((globalmode < 4) || flushline) && 94727228Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 948*27261Sminshall FD_CLR(net, &obits); 94927088Sminshall netflush(net); 95027110Sminshall } 9516000Sroot if (scc > 0) 9526000Sroot telrcv(); 953*27261Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) { 954*27261Sminshall FD_CLR(tout, &obits); 95527088Sminshall ttyflush(); 956*27261Sminshall } 9576000Sroot } 95827110Sminshall setcommandmode(); 9596000Sroot } 96027110Sminshall 9616000Sroot /* 9626000Sroot * Telnet receiver states for fsm 9636000Sroot */ 9646000Sroot #define TS_DATA 0 9656000Sroot #define TS_IAC 1 9666000Sroot #define TS_WILL 2 9676000Sroot #define TS_WONT 3 9686000Sroot #define TS_DO 4 9696000Sroot #define TS_DONT 5 97027021Sminshall #define TS_CR 6 9716000Sroot 9726000Sroot telrcv() 9736000Sroot { 9746000Sroot register int c; 9756000Sroot static int state = TS_DATA; 9766000Sroot 97727228Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 97827186Sminshall c = *sbp++ & 0xff, scc--; 9796000Sroot switch (state) { 9806000Sroot 98127021Sminshall case TS_CR: 98227021Sminshall state = TS_DATA; 98327228Sminshall if (c == '\0') { 98427228Sminshall break; /* Ignore \0 after CR */ 98527228Sminshall } else if (c == '\n') { 98627228Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 98727228Sminshall TTYADD(c); 98827228Sminshall } 98927228Sminshall break; 99027021Sminshall } 99127228Sminshall /* Else, fall through */ 99227021Sminshall 9936000Sroot case TS_DATA: 9949972Ssam if (c == IAC) { 9956000Sroot state = TS_IAC; 9969972Ssam continue; 9979972Ssam } 99827228Sminshall /* 99927228Sminshall * The 'crmod' hack (see following) is needed 100027228Sminshall * since we can't * set CRMOD on output only. 100127228Sminshall * Machines like MULTICS like to send \r without 100227228Sminshall * \n; since we must turn off CRMOD to get proper 100327228Sminshall * input, the mapping is done here (sigh). 100427228Sminshall */ 100527021Sminshall if (c == '\r') { 100627021Sminshall if (scc > 0) { 100727186Sminshall c = *sbp&0xff; 100827021Sminshall if (c == 0) { 100927021Sminshall sbp++, scc--; 101027228Sminshall /* a "true" CR */ 101127088Sminshall TTYADD('\r'); 101227021Sminshall } else if (!hisopts[TELOPT_ECHO] && 101327021Sminshall (c == '\n')) { 101427021Sminshall sbp++, scc--; 101527088Sminshall TTYADD('\n'); 101627021Sminshall } else { 101727088Sminshall TTYADD('\r'); 101827228Sminshall if (crmod) { 101927228Sminshall TTYADD('\n'); 102027228Sminshall } 102127021Sminshall } 102227021Sminshall } else { 102327021Sminshall state = TS_CR; 102427088Sminshall TTYADD('\r'); 102527228Sminshall if (crmod) { 102627228Sminshall TTYADD('\n'); 102727228Sminshall } 102827021Sminshall } 102927021Sminshall } else { 103027088Sminshall TTYADD(c); 103127021Sminshall } 10326000Sroot continue; 10336000Sroot 10346000Sroot case TS_IAC: 10356000Sroot switch (c) { 10366000Sroot 10376000Sroot case WILL: 10386000Sroot state = TS_WILL; 10396000Sroot continue; 10406000Sroot 10416000Sroot case WONT: 10426000Sroot state = TS_WONT; 10436000Sroot continue; 10446000Sroot 10456000Sroot case DO: 10466000Sroot state = TS_DO; 10476000Sroot continue; 10486000Sroot 10496000Sroot case DONT: 10506000Sroot state = TS_DONT; 10516000Sroot continue; 10526000Sroot 10536000Sroot case DM: 105427088Sminshall /* 105527088Sminshall * We may have missed an urgent notification, 105627088Sminshall * so make sure we flush whatever is in the 105727088Sminshall * buffer currently. 105827088Sminshall */ 105927186Sminshall SYNCHing = 1; 106027088Sminshall ttyflush(); 106127186Sminshall SYNCHing = stilloob(net); 106227178Sminshall settimer(gotDM); 10636000Sroot break; 10646000Sroot 10656000Sroot case NOP: 10666000Sroot case GA: 10676000Sroot break; 10686000Sroot 10696000Sroot default: 10706000Sroot break; 10716000Sroot } 10726000Sroot state = TS_DATA; 10736000Sroot continue; 10746000Sroot 10756000Sroot case TS_WILL: 10768345Ssam printoption("RCVD", will, c, !hisopts[c]); 107727110Sminshall if (c == TELOPT_TM) { 107827110Sminshall if (flushout) { 107927186Sminshall flushout = 0; 108027110Sminshall } 108127110Sminshall } else if (!hisopts[c]) { 10826000Sroot willoption(c); 108327110Sminshall } 10846000Sroot state = TS_DATA; 10856000Sroot continue; 10866000Sroot 10876000Sroot case TS_WONT: 10888345Ssam printoption("RCVD", wont, c, hisopts[c]); 108927110Sminshall if (c == TELOPT_TM) { 109027110Sminshall if (flushout) { 109127186Sminshall flushout = 0; 109227110Sminshall } 109327110Sminshall } else if (hisopts[c]) { 10946000Sroot wontoption(c); 109527110Sminshall } 10966000Sroot state = TS_DATA; 10976000Sroot continue; 10986000Sroot 10996000Sroot case TS_DO: 11008345Ssam printoption("RCVD", doopt, c, !myopts[c]); 11016000Sroot if (!myopts[c]) 11026000Sroot dooption(c); 11036000Sroot state = TS_DATA; 11046000Sroot continue; 11056000Sroot 11066000Sroot case TS_DONT: 11078345Ssam printoption("RCVD", dont, c, myopts[c]); 11086000Sroot if (myopts[c]) { 11096000Sroot myopts[c] = 0; 11106000Sroot sprintf(nfrontp, wont, c); 11118378Ssam nfrontp += sizeof (wont) - 2; 111227110Sminshall flushline = 1; 111327110Sminshall setconnmode(); /* set new tty mode (maybe) */ 11148345Ssam printoption("SENT", wont, c); 11156000Sroot } 11166000Sroot state = TS_DATA; 11176000Sroot continue; 11186000Sroot } 11196000Sroot } 11206000Sroot } 112127110Sminshall 11226000Sroot willoption(option) 11236000Sroot int option; 11246000Sroot { 11256000Sroot char *fmt; 11266000Sroot 11276000Sroot switch (option) { 11286000Sroot 11296000Sroot case TELOPT_ECHO: 11306000Sroot case TELOPT_SGA: 113127110Sminshall settimer(modenegotiated); 11326000Sroot hisopts[option] = 1; 11336000Sroot fmt = doopt; 113427110Sminshall setconnmode(); /* possibly set new tty mode */ 11356000Sroot break; 11366000Sroot 11376000Sroot case TELOPT_TM: 113827110Sminshall return; /* Never reply to TM will's/wont's */ 11396000Sroot 11406000Sroot default: 11416000Sroot fmt = dont; 11426000Sroot break; 11436000Sroot } 11446024Ssam sprintf(nfrontp, fmt, option); 11458378Ssam nfrontp += sizeof (dont) - 2; 11468345Ssam printoption("SENT", fmt, option); 11476000Sroot } 11486000Sroot 11496000Sroot wontoption(option) 11506000Sroot int option; 11516000Sroot { 11526000Sroot char *fmt; 11536000Sroot 11546000Sroot switch (option) { 11556000Sroot 11566000Sroot case TELOPT_ECHO: 11576000Sroot case TELOPT_SGA: 115827110Sminshall settimer(modenegotiated); 11596000Sroot hisopts[option] = 0; 11606000Sroot fmt = dont; 116127110Sminshall setconnmode(); /* Set new tty mode */ 11626000Sroot break; 11636000Sroot 116427110Sminshall case TELOPT_TM: 116527110Sminshall return; /* Never reply to TM will's/wont's */ 116627110Sminshall 11676000Sroot default: 11686000Sroot fmt = dont; 11696000Sroot } 11706000Sroot sprintf(nfrontp, fmt, option); 11718378Ssam nfrontp += sizeof (doopt) - 2; 11728345Ssam printoption("SENT", fmt, option); 11736000Sroot } 11746000Sroot 11756000Sroot dooption(option) 11766000Sroot int option; 11776000Sroot { 11786000Sroot char *fmt; 11796000Sroot 11806000Sroot switch (option) { 11816000Sroot 11826000Sroot case TELOPT_TM: 118313231Ssam fmt = will; 118413231Ssam break; 118513231Ssam 118627110Sminshall case TELOPT_SGA: /* no big deal */ 11876000Sroot fmt = will; 118827110Sminshall myopts[option] = 1; 11896000Sroot break; 11906000Sroot 119127110Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 11926000Sroot default: 11936000Sroot fmt = wont; 11946000Sroot break; 11956000Sroot } 11966000Sroot sprintf(nfrontp, fmt, option); 11978378Ssam nfrontp += sizeof (doopt) - 2; 11988345Ssam printoption("SENT", fmt, option); 11996000Sroot } 120027110Sminshall 12016000Sroot /* 120227088Sminshall * The following are data structures and routines for 120327088Sminshall * the "send" command. 120427088Sminshall * 120527088Sminshall */ 120627088Sminshall 120727088Sminshall struct sendlist { 120827088Sminshall char *name; /* How user refers to it (case independent) */ 120927088Sminshall int what; /* Character to be sent (<0 ==> special) */ 121027088Sminshall char *help; /* Help information (0 ==> no help) */ 121127088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 121227088Sminshall }; 121327088Sminshall 121427186Sminshall /*ARGSUSED*/ 121527088Sminshall dosynch(s) 121627088Sminshall struct sendlist *s; 121727088Sminshall { 1218*27261Sminshall netclear(); /* clear the path to the network */ 121927088Sminshall NET2ADD(IAC, DM); 122027186Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 122127088Sminshall } 122227088Sminshall 122327228Sminshall doflush() 122427228Sminshall { 122527228Sminshall NET2ADD(IAC, DO); 122627228Sminshall NETADD(TELOPT_TM); 122727228Sminshall printoption("SENT", doopt, TELOPT_TM); 122827228Sminshall flushline = 1; 122927228Sminshall flushout = 1; 123027228Sminshall ttyflush(); 123127228Sminshall } 123227228Sminshall 123327088Sminshall intp() 123427088Sminshall { 123527110Sminshall NET2ADD(IAC, IP); 123627228Sminshall if (autoflush) { 123727228Sminshall doflush(); 123827228Sminshall } 123927228Sminshall if (autosynch) { 124027228Sminshall dosynch(); 124127228Sminshall } 124227088Sminshall } 124327088Sminshall 124427110Sminshall sendbrk() 124527110Sminshall { 124627186Sminshall NET2ADD(IAC, BREAK); 124727228Sminshall if (autoflush) { 124827228Sminshall doflush(); 124927228Sminshall } 125027228Sminshall if (autosynch) { 125127228Sminshall dosynch(); 125227228Sminshall } 125327110Sminshall } 125427088Sminshall 125527110Sminshall 125627088Sminshall #define SENDQUESTION -1 125727088Sminshall #define SENDESCAPE -3 125827088Sminshall 125927088Sminshall struct sendlist Sendlist[] = { 126027088Sminshall { "ao", AO, "Send Telnet Abort output" }, 126127088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 1262*27261Sminshall { "brk", BREAK, "Send Telnet Break" }, 126327088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 126427088Sminshall { "el", EL, "Send Telnet Erase Line" }, 1265*27261Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 126627088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 1267*27261Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 126827088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 1269*27261Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 127027088Sminshall { "?", SENDQUESTION, "Display send options" }, 127127088Sminshall { 0 } 127227088Sminshall }; 127327088Sminshall 1274*27261Sminshall struct sendlist Sendlist2[] = { /* some synonyms */ 1275*27261Sminshall { "break", BREAK, 0 }, 1276*27261Sminshall 1277*27261Sminshall { "intp", IP, 0 }, 1278*27261Sminshall { "interrupt", IP, 0 }, 1279*27261Sminshall { "intr", IP, 0 }, 1280*27261Sminshall 1281*27261Sminshall { "help", SENDQUESTION, 0 }, 1282*27261Sminshall 1283*27261Sminshall { 0 } 1284*27261Sminshall }; 1285*27261Sminshall 128627088Sminshall char ** 128727088Sminshall getnextsend(name) 128827088Sminshall char *name; 128927088Sminshall { 129027088Sminshall struct sendlist *c = (struct sendlist *) name; 129127088Sminshall 129227088Sminshall return (char **) (c+1); 129327088Sminshall } 129427088Sminshall 129527088Sminshall struct sendlist * 129627088Sminshall getsend(name) 129727088Sminshall char *name; 129827088Sminshall { 1299*27261Sminshall struct sendlist *sl; 1300*27261Sminshall 1301*27261Sminshall if (sl = (struct sendlist *) 1302*27261Sminshall genget(name, (char **) Sendlist, getnextsend)) { 1303*27261Sminshall return sl; 1304*27261Sminshall } else { 1305*27261Sminshall return (struct sendlist *) 1306*27261Sminshall genget(name, (char **) Sendlist2, getnextsend); 1307*27261Sminshall } 130827088Sminshall } 130927088Sminshall 131027088Sminshall sendcmd(argc, argv) 131127088Sminshall int argc; 131227088Sminshall char **argv; 131327088Sminshall { 131427088Sminshall int what; /* what we are sending this time */ 131527088Sminshall int count; /* how many bytes we are going to need to send */ 131627088Sminshall int hadsynch; /* are we going to process a "synch"? */ 131727088Sminshall int i; 1318*27261Sminshall int question = 0; /* was at least one argument a question */ 131927088Sminshall struct sendlist *s; /* pointer to current command */ 132027088Sminshall 132127088Sminshall if (argc < 2) { 132227088Sminshall printf("need at least one argument for 'send' command\n"); 132327088Sminshall printf("'send ?' for help\n"); 1324*27261Sminshall return 0; 132527088Sminshall } 132627088Sminshall /* 132727088Sminshall * First, validate all the send arguments. 132827088Sminshall * In addition, we see how much space we are going to need, and 132927088Sminshall * whether or not we will be doing a "SYNCH" operation (which 133027088Sminshall * flushes the network queue). 133127088Sminshall */ 133227088Sminshall count = 0; 133327088Sminshall hadsynch = 0; 133427088Sminshall for (i = 1; i < argc; i++) { 133527088Sminshall s = getsend(argv[i]); 133627088Sminshall if (s == 0) { 133727088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 133827088Sminshall argv[i]); 1339*27261Sminshall return 0; 134027186Sminshall } else if (s == Ambiguous(struct sendlist *)) { 134127088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 134227088Sminshall argv[i]); 1343*27261Sminshall return 0; 134427088Sminshall } 134527088Sminshall switch (s->what) { 134627088Sminshall case SENDQUESTION: 134727088Sminshall break; 134827088Sminshall case SENDESCAPE: 134927088Sminshall count += 1; 135027088Sminshall break; 135127088Sminshall case SYNCH: 135227088Sminshall hadsynch = 1; 135327088Sminshall count += 2; 135427088Sminshall break; 135527088Sminshall default: 135627088Sminshall count += 2; 135727088Sminshall break; 135827088Sminshall } 135927088Sminshall } 136027088Sminshall /* Now, do we have enough room? */ 136127228Sminshall if (NETROOM() < count) { 136227088Sminshall printf("There is not enough room in the buffer TO the network\n"); 136327088Sminshall printf("to process your request. Nothing will be done.\n"); 136427088Sminshall printf("('send synch' will throw away most data in the network\n"); 136527088Sminshall printf("buffer, if this might help.)\n"); 1366*27261Sminshall return 0; 136727088Sminshall } 136827088Sminshall /* OK, they are all OK, now go through again and actually send */ 136927088Sminshall for (i = 1; i < argc; i++) { 137027088Sminshall if (!(s = getsend(argv[i]))) { 137127088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 137227088Sminshall quit(); 137327088Sminshall /*NOTREACHED*/ 137427088Sminshall } 137527088Sminshall if (s->routine) { 137627088Sminshall (*s->routine)(s); 137727088Sminshall } else { 137827088Sminshall switch (what = s->what) { 1379*27261Sminshall case SYNCH: 1380*27261Sminshall dosynch(); 1381*27261Sminshall break; 138227088Sminshall case SENDQUESTION: 138327088Sminshall for (s = Sendlist; s->name; s++) { 1384*27261Sminshall if (s->help) { 138527088Sminshall printf(s->name); 138627088Sminshall if (s->help) { 138727088Sminshall printf("\t%s", s->help); 138827088Sminshall } 138927088Sminshall printf("\n"); 139027088Sminshall } 139127088Sminshall } 1392*27261Sminshall question = 1; 139327088Sminshall break; 139427088Sminshall case SENDESCAPE: 139527088Sminshall NETADD(escape); 139627088Sminshall break; 139727088Sminshall default: 139827088Sminshall NET2ADD(IAC, what); 139927088Sminshall break; 140027088Sminshall } 140127088Sminshall } 140227088Sminshall } 1403*27261Sminshall return !question; 140427088Sminshall } 140527088Sminshall 140627088Sminshall /* 140727088Sminshall * The following are the routines and data structures referred 140827088Sminshall * to by the arguments to the "toggle" command. 140927088Sminshall */ 141027088Sminshall 1411*27261Sminshall lclchars() 141227110Sminshall { 1413*27261Sminshall donelclchars = 1; 1414*27261Sminshall return 1; 141527110Sminshall } 141627110Sminshall 141727178Sminshall togdebug() 141827088Sminshall { 141927110Sminshall if (net > 0 && 142027186Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug)) 142127186Sminshall < 0) { 142227110Sminshall perror("setsockopt (SO_DEBUG)"); 142327186Sminshall } 1424*27261Sminshall return 1; 142527088Sminshall } 142627088Sminshall 142727088Sminshall 142827088Sminshall 142927088Sminshall int togglehelp(); 143027088Sminshall 143127178Sminshall struct togglelist { 143227178Sminshall char *name; /* name of toggle */ 143327178Sminshall char *help; /* help message */ 143427186Sminshall int (*handler)(); /* routine to do actual setting */ 143527178Sminshall int dohelp; /* should we display help information */ 143627178Sminshall int *variable; 143727178Sminshall char *actionexplanation; 143827178Sminshall }; 143927178Sminshall 144027178Sminshall struct togglelist Togglelist[] = { 1441*27261Sminshall { "autoflush", 1442*27261Sminshall "toggle flushing of output when sending interrupt characters", 144327186Sminshall 0, 144427178Sminshall 1, 1445*27261Sminshall &autoflush, 1446*27261Sminshall "flush output when sending interrupt characters" }, 144727186Sminshall { "autosynch", 144827186Sminshall "toggle automatic sending of interrupt characters in urgent mode", 144927186Sminshall 0, 145027186Sminshall 1, 145127186Sminshall &autosynch, 145227186Sminshall "send interrupt characters in urgent mode" }, 145327178Sminshall { "crmod", 1454*27261Sminshall "toggle mapping of received carriage returns", 145527186Sminshall 0, 145627178Sminshall 1, 145727178Sminshall &crmod, 145827178Sminshall "map carriage return on output" }, 1459*27261Sminshall { "localchars", 1460*27261Sminshall "toggle local recognition of certain control characters", 1461*27261Sminshall lclchars, 1462*27261Sminshall 1, 1463*27261Sminshall &localchars, 1464*27261Sminshall "recognize certain control characters" }, 146527110Sminshall { " ", "", 0, 1 }, /* empty line */ 146627178Sminshall { "debug", 146727178Sminshall "(debugging) toggle debugging", 146827178Sminshall togdebug, 146927178Sminshall 1, 147027178Sminshall &debug, 147127178Sminshall "turn on socket level debugging" }, 1472*27261Sminshall { "netdata", 1473*27261Sminshall "(debugging) toggle printing of hexadecimal network data", 1474*27261Sminshall 0, 1475*27261Sminshall 1, 1476*27261Sminshall &netdata, 1477*27261Sminshall "print hexadecimal representation of network traffic" }, 147827178Sminshall { "options", 147927178Sminshall "(debugging) toggle viewing of options processing", 148027186Sminshall 0, 148127178Sminshall 1, 148227178Sminshall &showoptions, 148327178Sminshall "show option processing" }, 1484*27261Sminshall { " ", "", 0, 1 }, /* empty line */ 148527178Sminshall { "?", 148627178Sminshall "display help information", 148727178Sminshall togglehelp, 148827178Sminshall 1 }, 148927178Sminshall { "help", 149027178Sminshall "display help information", 149127178Sminshall togglehelp, 149227178Sminshall 0 }, 149327088Sminshall { 0 } 149427088Sminshall }; 149527088Sminshall 149627088Sminshall togglehelp() 149727088Sminshall { 149827178Sminshall struct togglelist *c; 149927088Sminshall 150027178Sminshall for (c = Togglelist; c->name; c++) { 150127088Sminshall if (c->dohelp) { 150227088Sminshall printf("%s\t%s\n", c->name, c->help); 150327088Sminshall } 150427088Sminshall } 1505*27261Sminshall return 0; 150627088Sminshall } 150727088Sminshall 150827088Sminshall char ** 150927088Sminshall getnexttoggle(name) 151027088Sminshall char *name; 151127088Sminshall { 151227178Sminshall struct togglelist *c = (struct togglelist *) name; 151327088Sminshall 151427088Sminshall return (char **) (c+1); 151527088Sminshall } 151627088Sminshall 151727178Sminshall struct togglelist * 151827088Sminshall gettoggle(name) 151927088Sminshall char *name; 152027088Sminshall { 152127178Sminshall return (struct togglelist *) 152227178Sminshall genget(name, (char **) Togglelist, getnexttoggle); 152327088Sminshall } 152427088Sminshall 152527088Sminshall toggle(argc, argv) 152627088Sminshall int argc; 152727088Sminshall char *argv[]; 152827088Sminshall { 1529*27261Sminshall int retval = 1; 153027088Sminshall char *name; 153127178Sminshall struct togglelist *c; 153227088Sminshall 153327088Sminshall if (argc < 2) { 153427088Sminshall fprintf(stderr, 153527088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 1536*27261Sminshall return 0; 153727088Sminshall } 153827088Sminshall argc--; 153927088Sminshall argv++; 154027088Sminshall while (argc--) { 154127088Sminshall name = *argv++; 154227088Sminshall c = gettoggle(name); 154327186Sminshall if (c == Ambiguous(struct togglelist *)) { 154427088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 154527088Sminshall name); 1546*27261Sminshall return 0; 154727088Sminshall } else if (c == 0) { 154827088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 154927088Sminshall name); 1550*27261Sminshall return 0; 155127088Sminshall } else { 155227186Sminshall if (c->variable) { 155327186Sminshall *c->variable = !*c->variable; /* invert it */ 155427186Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 155527186Sminshall c->actionexplanation); 155627186Sminshall } 155727186Sminshall if (c->handler) { 1558*27261Sminshall retval &= (*c->handler)(c); 155927186Sminshall } 156027088Sminshall } 156127088Sminshall } 1562*27261Sminshall return retval; 156327088Sminshall } 156427088Sminshall 156527088Sminshall /* 156627110Sminshall * The following perform the "set" command. 156727110Sminshall */ 156827110Sminshall 156927178Sminshall struct setlist { 157027178Sminshall char *name; /* name */ 157127110Sminshall char *help; /* help information */ 157227110Sminshall char *charp; /* where it is located at */ 157327110Sminshall }; 157427110Sminshall 157527178Sminshall struct setlist Setlist[] = { 157627110Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 157727110Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 1578*27261Sminshall { " ", "" }, 1579*27261Sminshall { " ", "The following need 'localchars' to be toggled true", 0 }, 1580*27261Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 1581*27261Sminshall { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc }, 158227110Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 1583*27261Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 158427110Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 158527110Sminshall { 0 } 158627110Sminshall }; 158727110Sminshall 158827110Sminshall char ** 158927178Sminshall getnextset(name) 159027110Sminshall char *name; 159127110Sminshall { 159227178Sminshall struct setlist *c = (struct setlist *)name; 159327110Sminshall 159427110Sminshall return (char **) (c+1); 159527110Sminshall } 159627110Sminshall 159727178Sminshall struct setlist * 159827178Sminshall getset(name) 159927110Sminshall char *name; 160027110Sminshall { 160127178Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 160227110Sminshall } 160327110Sminshall 160427110Sminshall setcmd(argc, argv) 160527110Sminshall int argc; 160627110Sminshall char *argv[]; 160727110Sminshall { 160827110Sminshall int value; 160927178Sminshall struct setlist *ct; 161027110Sminshall 161127110Sminshall /* XXX back we go... sigh */ 161227110Sminshall if (argc != 3) { 1613*27261Sminshall if ((argc == 2) && 1614*27261Sminshall ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) { 1615*27261Sminshall for (ct = Setlist; ct->name; ct++) { 1616*27261Sminshall printf("%s\t%s\n", ct->name, ct->help); 1617*27261Sminshall } 1618*27261Sminshall printf("?\tdisplay help information\n"); 1619*27261Sminshall } else { 1620*27261Sminshall printf("Format is 'set Name Value'\n'set ?' for help.\n"); 162127110Sminshall } 1622*27261Sminshall return 0; 162327110Sminshall } 162427110Sminshall 162527178Sminshall ct = getset(argv[1]); 162627110Sminshall if (ct == 0) { 162727110Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 162827110Sminshall argv[1]); 1629*27261Sminshall return 0; 163027186Sminshall } else if (ct == Ambiguous(struct setlist *)) { 163127110Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 163227110Sminshall argv[1]); 1633*27261Sminshall return 0; 163427110Sminshall } else { 163527110Sminshall if (strcmp("off", argv[2])) { 163627110Sminshall value = special(argv[2]); 163727110Sminshall } else { 163827110Sminshall value = -1; 163927110Sminshall } 164027110Sminshall *(ct->charp) = value; 164127178Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 164227110Sminshall } 1643*27261Sminshall return 1; 164427110Sminshall } 164527110Sminshall 164627110Sminshall /* 164727110Sminshall * The following are the data structures and routines for the 164827110Sminshall * 'mode' command. 164927110Sminshall */ 165027110Sminshall 165127110Sminshall dolinemode() 165227110Sminshall { 165327110Sminshall if (hisopts[TELOPT_SGA]) { 165427186Sminshall wontoption(TELOPT_SGA); 165527110Sminshall } 165627110Sminshall if (hisopts[TELOPT_ECHO]) { 165727186Sminshall wontoption(TELOPT_ECHO); 165827110Sminshall } 165927110Sminshall } 166027110Sminshall 166127110Sminshall docharmode() 166227110Sminshall { 166327110Sminshall if (!hisopts[TELOPT_SGA]) { 166427186Sminshall willoption(TELOPT_SGA); 166527110Sminshall } 166627110Sminshall if (!hisopts[TELOPT_ECHO]) { 166727186Sminshall willoption(TELOPT_ECHO); 166827110Sminshall } 166927110Sminshall } 167027110Sminshall 167127110Sminshall struct cmd Modelist[] = { 1672*27261Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 167327110Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 167427110Sminshall { 0 }, 167527110Sminshall }; 167627110Sminshall 167727110Sminshall char ** 167827110Sminshall getnextmode(name) 167927110Sminshall char *name; 168027110Sminshall { 168127110Sminshall struct cmd *c = (struct cmd *) name; 168227110Sminshall 168327110Sminshall return (char **) (c+1); 168427110Sminshall } 168527110Sminshall 168627110Sminshall struct cmd * 168727110Sminshall getmodecmd(name) 168827110Sminshall char *name; 168927110Sminshall { 169027110Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 169127110Sminshall } 169227110Sminshall 169327110Sminshall modecmd(argc, argv) 169427110Sminshall int argc; 169527110Sminshall char *argv[]; 169627110Sminshall { 169727110Sminshall struct cmd *mt; 169827110Sminshall 169927110Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 170027110Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 170127110Sminshall for (mt = Modelist; mt->name; mt++) { 170227110Sminshall printf("%s\t%s\n", mt->name, mt->help); 170327110Sminshall } 1704*27261Sminshall return 0; 170527110Sminshall } 170627110Sminshall mt = getmodecmd(argv[1]); 170727110Sminshall if (mt == 0) { 170827110Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 1709*27261Sminshall return 0; 171027186Sminshall } else if (mt == Ambiguous(struct cmd *)) { 171127110Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 1712*27261Sminshall return 0; 171327110Sminshall } else { 171427110Sminshall (*mt->handler)(); 171527110Sminshall } 1716*27261Sminshall return 1; 171727110Sminshall } 171827110Sminshall 171927110Sminshall /* 172027178Sminshall * The following data structures and routines implement the 172127178Sminshall * "display" command. 172227178Sminshall */ 172327178Sminshall 172427178Sminshall display(argc, argv) 172527178Sminshall int argc; 172627178Sminshall char *argv[]; 172727178Sminshall { 172827178Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 172927178Sminshall if (*tl->variable) { \ 173027178Sminshall printf("will"); \ 173127178Sminshall } else { \ 173227178Sminshall printf("won't"); \ 173327178Sminshall } \ 173427178Sminshall printf(" %s.\n", tl->actionexplanation); \ 173527178Sminshall } 173627178Sminshall 1737*27261Sminshall #define doset(sl) if (sl->name && *sl->name != ' ') { \ 1738*27261Sminshall printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \ 1739*27261Sminshall } 174027178Sminshall 174127178Sminshall struct togglelist *tl; 174227178Sminshall struct setlist *sl; 174327178Sminshall 174427178Sminshall if (argc == 1) { 174527178Sminshall for (tl = Togglelist; tl->name; tl++) { 174627178Sminshall dotog(tl); 174727178Sminshall } 1748*27261Sminshall printf("\n"); 174927178Sminshall for (sl = Setlist; sl->name; sl++) { 175027178Sminshall doset(sl); 175127178Sminshall } 175227178Sminshall } else { 175327178Sminshall int i; 175427178Sminshall 175527178Sminshall for (i = 1; i < argc; i++) { 175627178Sminshall sl = getset(argv[i]); 175727178Sminshall tl = gettoggle(argv[i]); 175827186Sminshall if ((sl == Ambiguous(struct setlist *)) || 175927186Sminshall (tl == Ambiguous(struct togglelist *))) { 176027178Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 1761*27261Sminshall return 0; 176227178Sminshall } else if (!sl && !tl) { 176327178Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 1764*27261Sminshall return 0; 176527178Sminshall } else { 176627186Sminshall if (tl) { 176727186Sminshall dotog(tl); 176827186Sminshall } 176927186Sminshall if (sl) { 177027186Sminshall doset(sl); 177127186Sminshall } 177227178Sminshall } 177327178Sminshall } 177427178Sminshall } 1775*27261Sminshall return 1; 177627178Sminshall #undef doset(sl) 177727178Sminshall #undef dotog(tl) 177827178Sminshall } 177927178Sminshall 178027178Sminshall /* 178127088Sminshall * The following are the data structures, and many of the routines, 178227088Sminshall * relating to command processing. 178327088Sminshall */ 178427088Sminshall 178527088Sminshall /* 178627088Sminshall * Set the escape character. 178727088Sminshall */ 178827088Sminshall setescape(argc, argv) 178927088Sminshall int argc; 179027088Sminshall char *argv[]; 179127088Sminshall { 179227088Sminshall register char *arg; 179327088Sminshall char buf[50]; 179427088Sminshall 179527186Sminshall printf( 179627186Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 179727186Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 179827088Sminshall if (argc > 2) 179927088Sminshall arg = argv[1]; 180027088Sminshall else { 180127088Sminshall printf("new escape character: "); 180227088Sminshall gets(buf); 180327088Sminshall arg = buf; 180427088Sminshall } 180527088Sminshall if (arg[0] != '\0') 180627088Sminshall escape = arg[0]; 180727088Sminshall printf("Escape character is '%s'.\n", control(escape)); 180827088Sminshall fflush(stdout); 1809*27261Sminshall return 1; 181027088Sminshall } 181127088Sminshall 181227088Sminshall /*VARARGS*/ 1813*27261Sminshall togcrmod() 1814*27261Sminshall { 1815*27261Sminshall crmod = !crmod; 1816*27261Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 1817*27261Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 1818*27261Sminshall fflush(stdout); 1819*27261Sminshall return 1; 1820*27261Sminshall } 1821*27261Sminshall 1822*27261Sminshall /*VARARGS*/ 182327088Sminshall suspend() 182427088Sminshall { 182527110Sminshall setcommandmode(); 182627088Sminshall kill(0, SIGTSTP); 182727088Sminshall /* reget parameters in case they were changed */ 182827088Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 182927088Sminshall ioctl(0, TIOCGETC, (char *)&otc); 183027088Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 1831*27261Sminshall return 1; 183227088Sminshall } 183327088Sminshall 183427088Sminshall /*VARARGS*/ 183527088Sminshall bye() 183627088Sminshall { 183727088Sminshall register char *op; 183827088Sminshall 183927088Sminshall if (connected) { 184027088Sminshall shutdown(net, 2); 184127088Sminshall printf("Connection closed.\n"); 184227088Sminshall close(net); 184327088Sminshall connected = 0; 184427088Sminshall /* reset his options */ 184527088Sminshall for (op = hisopts; op < &hisopts[256]; op++) 184627088Sminshall *op = 0; 184727088Sminshall } 1848*27261Sminshall return 1; 184927088Sminshall } 185027088Sminshall 185127088Sminshall /*VARARGS*/ 185227088Sminshall quit() 185327088Sminshall { 1854*27261Sminshall (void) call(bye, "bye", 0); 185527088Sminshall exit(0); 1856*27261Sminshall /*NOTREACHED*/ 185727088Sminshall } 185827088Sminshall 185927088Sminshall /* 186027088Sminshall * Print status about the connection. 186127088Sminshall */ 186227186Sminshall /*ARGSUSED*/ 186327178Sminshall status(argc, argv) 186427178Sminshall int argc; 186527178Sminshall char *argv[]; 186627088Sminshall { 186727178Sminshall if (connected) { 186827178Sminshall printf("Connected to %s.\n", hostname); 186927178Sminshall if (argc < 2) { 187027178Sminshall printf("Operating in %s.\n", modedescriptions[getconnmode()]); 1871*27261Sminshall if (localchars) { 187227178Sminshall printf("Catching signals locally.\n"); 187327178Sminshall } 187427110Sminshall } 187527178Sminshall } else { 187627178Sminshall printf("No connection.\n"); 187727178Sminshall } 187827178Sminshall printf("Escape character is '%s'.\n", control(escape)); 187927178Sminshall fflush(stdout); 1880*27261Sminshall return 1; 188127088Sminshall } 188227088Sminshall 188327088Sminshall tn(argc, argv) 188427088Sminshall int argc; 188527088Sminshall char *argv[]; 188627088Sminshall { 188727088Sminshall register struct hostent *host = 0; 188827088Sminshall 188927088Sminshall if (connected) { 189027088Sminshall printf("?Already connected to %s\n", hostname); 1891*27261Sminshall return 0; 189227088Sminshall } 189327088Sminshall if (argc < 2) { 189427186Sminshall (void) strcpy(line, "Connect "); 189527088Sminshall printf("(to) "); 189627088Sminshall gets(&line[strlen(line)]); 189727088Sminshall makeargv(); 189827088Sminshall argc = margc; 189927088Sminshall argv = margv; 190027088Sminshall } 190127088Sminshall if (argc > 3) { 190227088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 1903*27261Sminshall return 0; 190427088Sminshall } 190527088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 190627088Sminshall if (sin.sin_addr.s_addr != -1) { 190727088Sminshall sin.sin_family = AF_INET; 190827186Sminshall (void) strcpy(hnamebuf, argv[1]); 190927088Sminshall hostname = hnamebuf; 191027088Sminshall } else { 191127088Sminshall host = gethostbyname(argv[1]); 191227088Sminshall if (host) { 191327088Sminshall sin.sin_family = host->h_addrtype; 191427088Sminshall bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 191527088Sminshall host->h_length); 191627088Sminshall hostname = host->h_name; 191727088Sminshall } else { 191827088Sminshall printf("%s: unknown host\n", argv[1]); 1919*27261Sminshall return 0; 192027088Sminshall } 192127088Sminshall } 192227088Sminshall sin.sin_port = sp->s_port; 192327088Sminshall if (argc == 3) { 192427088Sminshall sin.sin_port = atoi(argv[2]); 192527186Sminshall if (sin.sin_port == 0) { 192627088Sminshall sp = getservbyname(argv[2], "tcp"); 192727088Sminshall if (sp) 192827088Sminshall sin.sin_port = sp->s_port; 192927088Sminshall else { 193027088Sminshall printf("%s: bad port number\n", argv[2]); 1931*27261Sminshall return 0; 193227088Sminshall } 193327088Sminshall } else { 193427088Sminshall sin.sin_port = atoi(argv[2]); 193527088Sminshall sin.sin_port = htons(sin.sin_port); 193627088Sminshall } 193727088Sminshall telnetport = 0; 193827110Sminshall } else { 193927110Sminshall telnetport = 1; 194027088Sminshall } 194127088Sminshall signal(SIGINT, intr); 194227110Sminshall signal(SIGQUIT, intr2); 194327088Sminshall signal(SIGPIPE, deadpeer); 194427088Sminshall printf("Trying...\n"); 194527088Sminshall do { 194627088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 194727088Sminshall if (net < 0) { 194827088Sminshall perror("telnet: socket"); 1949*27261Sminshall return 0; 195027088Sminshall } 195127186Sminshall if (debug && 195227186Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, 195327186Sminshall (char *)&debug, sizeof(debug)) < 0) { 195427088Sminshall perror("setsockopt (SO_DEBUG)"); 195527186Sminshall } 195627186Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 195727088Sminshall if (host && host->h_addr_list[1]) { 195827088Sminshall int oerrno = errno; 195927088Sminshall 196027088Sminshall fprintf(stderr, 196127088Sminshall "telnet: connect to address %s: ", 196227088Sminshall inet_ntoa(sin.sin_addr)); 196327088Sminshall errno = oerrno; 196427186Sminshall perror((char *)0); 196527088Sminshall host->h_addr_list++; 196627088Sminshall bcopy(host->h_addr_list[0], 196727088Sminshall (caddr_t)&sin.sin_addr, host->h_length); 196827088Sminshall fprintf(stderr, "Trying %s...\n", 196927088Sminshall inet_ntoa(sin.sin_addr)); 197027088Sminshall (void) close(net); 197127088Sminshall continue; 197227088Sminshall } 197327088Sminshall perror("telnet: connect"); 197427088Sminshall signal(SIGINT, SIG_DFL); 1975*27261Sminshall signal(SIGQUIT, SIG_DFL); 1976*27261Sminshall return 0; 197727088Sminshall } 197827088Sminshall connected++; 197927088Sminshall } while (connected == 0); 198027178Sminshall call(status, "status", "notmuch", 0); 198127088Sminshall if (setjmp(peerdied) == 0) 198227088Sminshall telnet(); 198327088Sminshall fprintf(stderr, "Connection closed by foreign host.\n"); 198427088Sminshall exit(1); 1985*27261Sminshall /*NOTREACHED*/ 198627088Sminshall } 198727088Sminshall 198827088Sminshall 198927088Sminshall #define HELPINDENT (sizeof ("connect")) 199027088Sminshall 199127088Sminshall char openhelp[] = "connect to a site"; 199227088Sminshall char closehelp[] = "close current connection"; 199327088Sminshall char quithelp[] = "exit telnet"; 199427088Sminshall char zhelp[] = "suspend telnet"; 199527088Sminshall char statushelp[] = "print status information"; 199627088Sminshall char helphelp[] = "print help information"; 199727110Sminshall char sendhelp[] = "transmit special characters ('send ?' for more)"; 199827178Sminshall char sethelp[] = "set operating parameters ('set ?' for more)"; 199927178Sminshall char togglestring[] ="toggle operating parameters ('toggle ?' for more)"; 200027178Sminshall char displayhelp[] = "display operating parameters"; 200127178Sminshall char modehelp[] = 200227178Sminshall "try to enter line-by-line or character-at-a-time mode"; 200327088Sminshall 200427088Sminshall int help(); 200527088Sminshall 200627088Sminshall struct cmd cmdtab[] = { 2007*27261Sminshall { "close", closehelp, bye, 1, 1 }, 2008*27261Sminshall { "display", displayhelp, display, 1, 0 }, 2009*27261Sminshall { "mode", modehelp, modecmd, 1, 1 }, 201027110Sminshall { "open", openhelp, tn, 1, 0 }, 201127110Sminshall { "quit", quithelp, quit, 1, 0 }, 201227110Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 201327178Sminshall { "set", sethelp, setcmd, 1, 0 }, 2014*27261Sminshall { "status", statushelp, status, 1, 0 }, 201527110Sminshall { "toggle", togglestring, toggle, 1, 0 }, 2016*27261Sminshall { "z", zhelp, suspend, 1, 0 }, 201727110Sminshall { "?", helphelp, help, 1, 0 }, 2018*27261Sminshall 0 2019*27261Sminshall }; 2020*27261Sminshall 2021*27261Sminshall char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 2022*27261Sminshall char escapehelp[] = "deprecated command -- use 'set escape' instead"; 2023*27261Sminshall 2024*27261Sminshall struct cmd cmdtab2[] = { 202527110Sminshall { "help", helphelp, help, 0, 0 }, 2026*27261Sminshall { "escape", escapehelp, setescape, 1, 0 }, 2027*27261Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 202827088Sminshall 0 202927088Sminshall }; 203027088Sminshall 203127088Sminshall /* 203227088Sminshall * Help command. 203327088Sminshall */ 203427088Sminshall help(argc, argv) 203527088Sminshall int argc; 203627088Sminshall char *argv[]; 203727088Sminshall { 203827088Sminshall register struct cmd *c; 203927088Sminshall 204027088Sminshall if (argc == 1) { 204127088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 204227088Sminshall for (c = cmdtab; c->name; c++) 204327088Sminshall if (c->dohelp) { 204427088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 204527088Sminshall c->help); 204627088Sminshall } 2047*27261Sminshall return 0; 204827088Sminshall } 204927088Sminshall while (--argc > 0) { 205027088Sminshall register char *arg; 205127088Sminshall arg = *++argv; 205227088Sminshall c = getcmd(arg); 205327186Sminshall if (c == Ambiguous(struct cmd *)) 205427088Sminshall printf("?Ambiguous help command %s\n", arg); 205527088Sminshall else if (c == (struct cmd *)0) 205627088Sminshall printf("?Invalid help command %s\n", arg); 205727088Sminshall else 205827088Sminshall printf("%s\n", c->help); 205927088Sminshall } 2060*27261Sminshall return 0; 206127088Sminshall } 206227088Sminshall /* 206327088Sminshall * Call routine with argc, argv set from args (terminated by 0). 206427088Sminshall * VARARGS2 206527088Sminshall */ 206627088Sminshall call(routine, args) 206727088Sminshall int (*routine)(); 206827186Sminshall char *args; 206927088Sminshall { 207027186Sminshall register char **argp; 207127088Sminshall register int argc; 207227088Sminshall 207327088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 207427088Sminshall ; 2075*27261Sminshall return (*routine)(argc, &args); 207627088Sminshall } 207727088Sminshall 207827088Sminshall makeargv() 207927088Sminshall { 208027088Sminshall register char *cp; 208127088Sminshall register char **argp = margv; 208227088Sminshall 208327088Sminshall margc = 0; 208427088Sminshall for (cp = line; *cp;) { 208527088Sminshall while (isspace(*cp)) 208627088Sminshall cp++; 208727088Sminshall if (*cp == '\0') 208827088Sminshall break; 208927088Sminshall *argp++ = cp; 209027088Sminshall margc += 1; 209127088Sminshall while (*cp != '\0' && !isspace(*cp)) 209227088Sminshall cp++; 209327088Sminshall if (*cp == '\0') 209427088Sminshall break; 209527088Sminshall *cp++ = '\0'; 209627088Sminshall } 209727088Sminshall *argp++ = 0; 209827088Sminshall } 209927088Sminshall 210027088Sminshall char ** 210127088Sminshall getnextcmd(name) 210227088Sminshall char *name; 210327088Sminshall { 210427088Sminshall struct cmd *c = (struct cmd *) name; 210527088Sminshall 210627088Sminshall return (char **) (c+1); 210727088Sminshall } 210827088Sminshall 210927088Sminshall struct cmd * 211027088Sminshall getcmd(name) 211127088Sminshall char *name; 211227088Sminshall { 2113*27261Sminshall struct cmd *cm; 2114*27261Sminshall 2115*27261Sminshall if (cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) { 2116*27261Sminshall return cm; 2117*27261Sminshall } else { 2118*27261Sminshall return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd); 2119*27261Sminshall } 212027088Sminshall } 212127088Sminshall 212227088Sminshall command(top) 212327088Sminshall int top; 212427088Sminshall { 212527088Sminshall register struct cmd *c; 212627088Sminshall 212727110Sminshall setcommandmode(); 2128*27261Sminshall if (!top) { 212927088Sminshall putchar('\n'); 2130*27261Sminshall } else { 213127088Sminshall signal(SIGINT, SIG_DFL); 2132*27261Sminshall signal(SIGQUIT, SIG_DFL); 2133*27261Sminshall } 213427088Sminshall for (;;) { 213527088Sminshall printf("%s> ", prompt); 213627088Sminshall if (gets(line) == 0) { 213727088Sminshall if (feof(stdin)) 213827088Sminshall quit(); 213927088Sminshall break; 214027088Sminshall } 214127088Sminshall if (line[0] == 0) 214227088Sminshall break; 214327088Sminshall makeargv(); 214427088Sminshall c = getcmd(margv[0]); 214527186Sminshall if (c == Ambiguous(struct cmd *)) { 214627088Sminshall printf("?Ambiguous command\n"); 214727088Sminshall continue; 214827088Sminshall } 214927088Sminshall if (c == 0) { 215027088Sminshall printf("?Invalid command\n"); 215127088Sminshall continue; 215227088Sminshall } 215327088Sminshall if (c->needconnect && !connected) { 215427088Sminshall printf("?Need to be connected first.\n"); 215527088Sminshall continue; 215627088Sminshall } 2157*27261Sminshall if ((*c->handler)(margc, margv)) { 215827088Sminshall break; 2159*27261Sminshall } 216027088Sminshall } 216127088Sminshall if (!top) { 216227110Sminshall if (!connected) { 216327088Sminshall longjmp(toplevel, 1); 216427110Sminshall /*NOTREACHED*/ 216527110Sminshall } 216627110Sminshall setconnmode(); 216727088Sminshall } 216827088Sminshall } 216927186Sminshall 217027186Sminshall /* 217127186Sminshall * main. Parse arguments, invoke the protocol or command parser. 217227186Sminshall */ 217327186Sminshall 217427186Sminshall 217527186Sminshall main(argc, argv) 217627186Sminshall int argc; 217727186Sminshall char *argv[]; 217827186Sminshall { 217927186Sminshall sp = getservbyname("telnet", "tcp"); 218027186Sminshall if (sp == 0) { 218127186Sminshall fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 218227186Sminshall exit(1); 218327186Sminshall } 218427186Sminshall NetTrace = stdout; 218527186Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 218627186Sminshall ioctl(0, TIOCGETC, (char *)&otc); 218727186Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 218827228Sminshall #if defined(LNOFLSH) 218927228Sminshall ioctl(0, TIOCLGET, (char *)&autoflush); 2190*27261Sminshall autoflush = !(autoflush&LNOFLSH); /* if LNOFLSH, no autoflush */ 2191*27261Sminshall #else /* LNOFLSH */ 2192*27261Sminshall autoflush = 1; 219327228Sminshall #endif /* LNOFLSH */ 219427186Sminshall ntc = otc; 219527186Sminshall ntc.t_eofc = -1; /* we don't want to use EOF */ 219627228Sminshall nltc = oltc; 219727186Sminshall nttyb = ottyb; 219827186Sminshall setbuf(stdin, (char *)0); 219927186Sminshall setbuf(stdout, (char *)0); 220027186Sminshall prompt = argv[0]; 220127186Sminshall if (argc > 1 && !strcmp(argv[1], "-d")) { 220227186Sminshall debug = 1; 220327186Sminshall argv++; 220427186Sminshall argc--; 220527186Sminshall } 220627186Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 220727186Sminshall argv++; 220827186Sminshall argc--; 220927186Sminshall if (argc > 1) { /* get file name */ 221027186Sminshall NetTrace = fopen(argv[1], "w"); 221127186Sminshall argv++; 221227186Sminshall argc--; 221327186Sminshall if (NetTrace == NULL) { 221427186Sminshall NetTrace = stdout; 221527186Sminshall } 221627186Sminshall } 221727186Sminshall } 221827186Sminshall if (argc != 1) { 221927186Sminshall if (setjmp(toplevel) != 0) 222027186Sminshall exit(0); 222127186Sminshall tn(argc, argv); 222227186Sminshall } 222327186Sminshall setjmp(toplevel); 222427186Sminshall for (;;) 222527186Sminshall command(1); 222627186Sminshall } 2227