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*27228Sminshall static char sccsid[] = "@(#)telnet.c 5.11 (Berkeley) 04/20/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 58*27228Sminshall #define strip(x) ((x)&0x7f) 596000Sroot 60*27228Sminshall char ttyobuf[2*BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; 61*27228Sminshall #define TTYADD(c) { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } } 62*27228Sminshall #define TTYLOC() (tfrontp) 63*27228Sminshall #define TTYMAX() (ttyobuf+sizeof ttyobuf-1) 64*27228Sminshall #define TTYMIN() (netobuf) 65*27228Sminshall #define TTYBYTES() (tfrontp-tbackp) 66*27228Sminshall #define TTYROOM() (TTYMAX()-TTYLOC()+1) 6727088Sminshall 68*27228Sminshall 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) 72*27228Sminshall #define NETMAX() (netobuf+sizeof netobuf-1) 73*27228Sminshall #define NETBYTES() (nfrontp-nbackp) 74*27228Sminshall #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 */ 110*27228Sminshall int autoflush = 0; /* flush output when interrupting? */ 11127186Sminshall int autosynch = 0; /* send interrupt characters with SYNCH? */ 11227186Sminshall int localsigs = 0; /* we recognize interrupt/quit */ 11327186Sminshall int donelclsigs = 0; /* the user has set "localsigs" */ 11427186Sminshall int doechocharrecognition = 1; /* in line mode recognize echo toggle */ 11527186Sminshall int dontlecho = 0; /* do we suppress local echoing right now? */ 11627186Sminshall 1176000Sroot char line[200]; 1186000Sroot int margc; 1196000Sroot char *margv[20]; 1206000Sroot 1216000Sroot jmp_buf toplevel; 1226000Sroot jmp_buf peerdied; 1236000Sroot 1246000Sroot extern int errno; 1256000Sroot 1266000Sroot 1279972Ssam struct sockaddr_in sin; 1286000Sroot 1296000Sroot struct cmd *getcmd(); 1308345Ssam struct servent *sp; 1316000Sroot 13227110Sminshall struct tchars otc, ntc; 133*27228Sminshall struct ltchars oltc, nltc; 13427110Sminshall struct sgttyb ottyb, nttyb; 13527110Sminshall int globalmode = 0; 13627110Sminshall int flushline = 1; 1378378Ssam 13827110Sminshall char *hostname; 13927110Sminshall char hnamebuf[32]; 14027110Sminshall 14127110Sminshall /* 14227110Sminshall * The following are some clocks used to decide how to interpret 14327178Sminshall * the relationship between various variables. 14427110Sminshall */ 14527110Sminshall 14627110Sminshall struct { 14727110Sminshall int 14827110Sminshall system, /* what the current time is */ 14927110Sminshall echotoggle, /* last time user entered echo character */ 15027178Sminshall modenegotiated, /* last time operating mode negotiated */ 15127178Sminshall didnetreceive, /* last time we read data from network */ 15227178Sminshall gotDM; /* when did we last see a data mark */ 15327186Sminshall } clocks; 15427110Sminshall 15527186Sminshall #define settimer(x) clocks.x = clocks.system++ 15627110Sminshall 15727110Sminshall /* 15827110Sminshall * Various utility routines. 15927110Sminshall */ 1606000Sroot 16127186Sminshall char *ambiguous; /* special return value */ 16227186Sminshall #define Ambiguous(t) ((t)&ambiguous) 16327186Sminshall 16427186Sminshall 16527088Sminshall char ** 16627088Sminshall genget(name, table, next) 16727088Sminshall char *name; /* name to match */ 16827088Sminshall char **table; /* name entry in table */ 16927088Sminshall char **(*next)(); /* routine to return next entry in table */ 1706000Sroot { 17127088Sminshall register char *p, *q; 17227088Sminshall register char **c, **found; 17327088Sminshall register int nmatches, longest; 1746000Sroot 17527088Sminshall longest = 0; 17627088Sminshall nmatches = 0; 17727088Sminshall found = 0; 17827088Sminshall for (c = table; p = *c; c = (*next)(c)) { 17927088Sminshall for (q = name; *q == *p++; q++) 18027088Sminshall if (*q == 0) /* exact match? */ 18127088Sminshall return (c); 18227088Sminshall if (!*q) { /* the name was a prefix */ 18327088Sminshall if (q - name > longest) { 18427088Sminshall longest = q - name; 18527088Sminshall nmatches = 1; 18627088Sminshall found = c; 18727088Sminshall } else if (q - name == longest) 18827088Sminshall nmatches++; 1898377Ssam } 1906000Sroot } 19127088Sminshall if (nmatches > 1) 19227186Sminshall return Ambiguous(char **); 19327088Sminshall return (found); 1946000Sroot } 1956000Sroot 19627110Sminshall /* 19727110Sminshall * Make a character string into a number. 19827110Sminshall * 19927186Sminshall * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 20027110Sminshall */ 2016000Sroot 20227110Sminshall special(s) 20327110Sminshall register char *s; 20427110Sminshall { 20527110Sminshall register char c; 20627110Sminshall char b; 20727110Sminshall 20827110Sminshall switch (*s) { 20927110Sminshall case '^': 21027110Sminshall b = *++s; 21127110Sminshall if (b == '?') { 212*27228Sminshall c = b | 0x40; /* DEL */ 21327110Sminshall } else { 21427110Sminshall c = b & 0x1f; 21527110Sminshall } 21627110Sminshall break; 21727110Sminshall default: 21827110Sminshall c = *s; 21927110Sminshall break; 22027110Sminshall } 22127110Sminshall return c; 22227110Sminshall } 22327186Sminshall 22427186Sminshall /* 22527186Sminshall * Construct a control character sequence 22627186Sminshall * for a special character. 22727186Sminshall */ 22827186Sminshall char * 22927186Sminshall control(c) 23027186Sminshall register int c; 23127186Sminshall { 23227186Sminshall static char buf[3]; 23327186Sminshall 234*27228Sminshall if (c == 0x7f) 23527186Sminshall return ("^?"); 23627186Sminshall if (c == '\377') { 23727186Sminshall return "off"; 23827186Sminshall } 23927186Sminshall if (c >= 0x20) { 24027186Sminshall buf[0] = c; 24127186Sminshall buf[1] = 0; 24227186Sminshall } else { 24327186Sminshall buf[0] = '^'; 24427186Sminshall buf[1] = '@'+c; 24527186Sminshall buf[2] = 0; 24627186Sminshall } 24727186Sminshall return (buf); 24827186Sminshall } 24927110Sminshall 25027110Sminshall /* 25127186Sminshall * Check to see if any out-of-band data exists on a socket (for 25227186Sminshall * Telnet "synch" processing). 25327186Sminshall */ 25427186Sminshall 25527186Sminshall int 25627186Sminshall stilloob(s) 25727186Sminshall int s; /* socket number */ 25827186Sminshall { 25927186Sminshall static struct timeval timeout = { 0 }; 26027186Sminshall fd_set excepts; 26127186Sminshall int value; 26227186Sminshall 26327186Sminshall do { 26427186Sminshall FD_ZERO(&excepts); 26527186Sminshall FD_SET(s, &excepts); 26627186Sminshall value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 26727186Sminshall } while ((value == -1) && (errno = EINTR)); 26827186Sminshall 26927186Sminshall if (value < 0) { 27027186Sminshall perror("select"); 27127186Sminshall quit(); 27227186Sminshall } 27327186Sminshall if (FD_ISSET(s, &excepts)) { 27427186Sminshall return 1; 27527186Sminshall } else { 27627186Sminshall return 0; 27727186Sminshall } 27827186Sminshall } 27927186Sminshall 28027186Sminshall 28127186Sminshall /* 28227186Sminshall * netflush 28327186Sminshall * Send as much data as possible to the network, 28427186Sminshall * handling requests for urgent data. 28527186Sminshall */ 28627186Sminshall 28727186Sminshall 28827186Sminshall netflush(fd) 28927186Sminshall { 29027186Sminshall int n; 29127186Sminshall 29227186Sminshall if ((n = nfrontp - nbackp) > 0) { 29327186Sminshall if (!neturg) { 29427186Sminshall n = write(fd, nbackp, n); /* normal write */ 29527186Sminshall } else { 29627186Sminshall n = neturg - nbackp; 29727186Sminshall /* 29827186Sminshall * In 4.2 (and 4.3) systems, there is some question about 29927186Sminshall * what byte in a sendOOB operation is the "OOB" data. 30027186Sminshall * To make ourselves compatible, we only send ONE byte 30127186Sminshall * out of band, the one WE THINK should be OOB (though 30227186Sminshall * we really have more the TCP philosophy of urgent data 30327186Sminshall * rather than the Unix philosophy of OOB data). 30427186Sminshall */ 30527186Sminshall if (n > 1) { 30627186Sminshall n = send(fd, nbackp, n-1, 0); /* send URGENT all by itself */ 30727186Sminshall } else { 30827186Sminshall n = send(fd, nbackp, n, MSG_OOB); /* URGENT data */ 30927186Sminshall } 31027186Sminshall } 31127186Sminshall } 31227186Sminshall if (n < 0) { 31327186Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 31427186Sminshall setcommandmode(); 31527186Sminshall perror(hostname); 31627186Sminshall close(fd); 31727186Sminshall neturg = 0; 31827186Sminshall longjmp(peerdied, -1); 31927186Sminshall /*NOTREACHED*/ 32027186Sminshall } 32127186Sminshall n = 0; 32227186Sminshall } 32327186Sminshall if (netdata && n) { 32427186Sminshall Dump('>', nbackp, n); 32527186Sminshall } 32627186Sminshall nbackp += n; 32727186Sminshall if (nbackp >= neturg) { 32827186Sminshall neturg = 0; 32927186Sminshall } 33027186Sminshall if (nbackp == nfrontp) { 33127186Sminshall nbackp = nfrontp = netobuf; 33227186Sminshall } 33327186Sminshall } 33427186Sminshall 33527186Sminshall /* 33627186Sminshall * Send as much data as possible to the terminal. 33727186Sminshall */ 33827186Sminshall 33927186Sminshall 34027186Sminshall ttyflush() 34127186Sminshall { 34227186Sminshall int n; 34327186Sminshall 34427186Sminshall if ((n = tfrontp - tbackp) > 0) { 345*27228Sminshall if (!(SYNCHing||flushout)) { 34627186Sminshall n = write(tout, tbackp, n); 34727186Sminshall } else { 34827186Sminshall ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 349*27228Sminshall /* we leave 'n' alone! */ 35027186Sminshall } 35127186Sminshall } 35227186Sminshall if (n < 0) { 35327186Sminshall return; 35427186Sminshall } 35527186Sminshall tbackp += n; 35627186Sminshall if (tbackp == tfrontp) { 35727186Sminshall tbackp = tfrontp = ttyobuf; 35827186Sminshall } 35927186Sminshall } 36027186Sminshall 36127186Sminshall /* 36227110Sminshall * Various signal handling routines. 36327110Sminshall */ 36427110Sminshall 36527110Sminshall deadpeer() 36627110Sminshall { 36727110Sminshall setcommandmode(); 36827110Sminshall longjmp(peerdied, -1); 36927110Sminshall } 37027110Sminshall 37127110Sminshall intr() 37227110Sminshall { 37327110Sminshall if (localsigs) { 37427110Sminshall intp(); 37527110Sminshall return; 37627110Sminshall } 37727110Sminshall setcommandmode(); 37827110Sminshall longjmp(toplevel, -1); 37927110Sminshall } 38027110Sminshall 38127110Sminshall intr2() 38227110Sminshall { 38327110Sminshall if (localsigs) { 38427110Sminshall sendbrk(); 38527110Sminshall return; 38627110Sminshall } 38727110Sminshall } 38827110Sminshall 38927110Sminshall doescape() 39027110Sminshall { 39127110Sminshall command(0); 39227110Sminshall } 39327110Sminshall 39427110Sminshall /* 39527186Sminshall * The following are routines used to print out debugging information. 39627186Sminshall */ 39727186Sminshall 39827186Sminshall 39927186Sminshall static 40027186Sminshall Dump(direction, buffer, length) 40127186Sminshall char direction; 40227186Sminshall char *buffer; 40327186Sminshall int length; 40427186Sminshall { 40527186Sminshall # define BYTES_PER_LINE 32 40627186Sminshall # define min(x,y) ((x<y)? x:y) 40727186Sminshall char *pThis; 40827186Sminshall int offset; 40927186Sminshall 41027186Sminshall offset = 0; 41127186Sminshall 41227186Sminshall while (length) { 41327186Sminshall /* print one line */ 41427186Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 41527186Sminshall pThis = buffer; 41627186Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 41727186Sminshall while (pThis < buffer) { 41827186Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 41927186Sminshall pThis++; 42027186Sminshall } 42127186Sminshall fprintf(NetTrace, "\n"); 42227186Sminshall length -= BYTES_PER_LINE; 42327186Sminshall offset += BYTES_PER_LINE; 42427186Sminshall if (length < 0) { 42527186Sminshall return; 42627186Sminshall } 42727186Sminshall /* find next unique line */ 42827186Sminshall } 42927186Sminshall } 43027186Sminshall 43127186Sminshall 43227186Sminshall /*VARARGS*/ 43327186Sminshall printoption(direction, fmt, option, what) 43427186Sminshall char *direction, *fmt; 43527186Sminshall int option, what; 43627186Sminshall { 43727186Sminshall if (!showoptions) 43827186Sminshall return; 43927186Sminshall printf("%s ", direction); 44027186Sminshall if (fmt == doopt) 44127186Sminshall fmt = "do"; 44227186Sminshall else if (fmt == dont) 44327186Sminshall fmt = "dont"; 44427186Sminshall else if (fmt == will) 44527186Sminshall fmt = "will"; 44627186Sminshall else if (fmt == wont) 44727186Sminshall fmt = "wont"; 44827186Sminshall else 44927186Sminshall fmt = "???"; 45027186Sminshall if (option < TELOPT_SUPDUP) 45127186Sminshall printf("%s %s", fmt, telopts[option]); 45227186Sminshall else 45327186Sminshall printf("%s %d", fmt, option); 45427186Sminshall if (*direction == '<') { 45527186Sminshall printf("\r\n"); 45627186Sminshall return; 45727186Sminshall } 45827186Sminshall printf(" (%s)\r\n", what ? "reply" : "don't reply"); 45927186Sminshall } 46027186Sminshall 46127186Sminshall /* 46227110Sminshall * Mode - set up terminal to a specific mode. 46327110Sminshall */ 46427110Sminshall 4659972Ssam 4666000Sroot mode(f) 4676000Sroot register int f; 4686000Sroot { 4698378Ssam static int prevmode = 0; 47013076Ssam struct tchars *tc; 47113076Ssam struct ltchars *ltc; 47213076Ssam struct sgttyb sb; 47313076Ssam int onoff, old; 474*27228Sminshall struct tchars notc2; 475*27228Sminshall struct ltchars noltc2; 476*27228Sminshall static struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 477*27228Sminshall static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 4786000Sroot 47927110Sminshall globalmode = f; 4808378Ssam if (prevmode == f) 48127186Sminshall return; 4828378Ssam old = prevmode; 4838378Ssam prevmode = f; 48427110Sminshall sb = nttyb; 4856000Sroot switch (f) { 4868378Ssam 4876000Sroot case 0: 4886000Sroot onoff = 0; 4899972Ssam tc = &otc; 49013076Ssam ltc = &oltc; 4916000Sroot break; 4926000Sroot 49327110Sminshall case 1: /* remote character processing, remote echo */ 49427110Sminshall case 2: /* remote character processing, local echo */ 49513076Ssam sb.sg_flags |= CBREAK; 4968378Ssam if (f == 1) 49713076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 4988378Ssam else 49913076Ssam sb.sg_flags |= ECHO|CRMOD; 50013076Ssam sb.sg_erase = sb.sg_kill = -1; 5019972Ssam tc = ¬c; 50227110Sminshall /* 50327110Sminshall * If user hasn't specified one way or the other, 50427110Sminshall * then default to not trapping signals. 50527110Sminshall */ 506*27228Sminshall if (!donelclsigs) { 50727110Sminshall localsigs = 0; 508*27228Sminshall } 50927110Sminshall if (localsigs) { 51027110Sminshall notc2 = notc; 51127110Sminshall notc2.t_intrc = ntc.t_intrc; 51227110Sminshall notc2.t_quitc = ntc.t_quitc; 51327110Sminshall tc = ¬c2; 51427110Sminshall } else 51527110Sminshall tc = ¬c; 51613076Ssam ltc = &noltc; 5176000Sroot onoff = 1; 5189972Ssam break; 51927110Sminshall case 3: /* local character processing, remote echo */ 52027110Sminshall case 4: /* local character processing, local echo */ 52127110Sminshall case 5: /* local character processing, no echo */ 52227110Sminshall sb.sg_flags &= ~CBREAK; 52327110Sminshall sb.sg_flags |= CRMOD; 52427110Sminshall if (f == 4) 52527110Sminshall sb.sg_flags |= ECHO; 52627110Sminshall else 52727110Sminshall sb.sg_flags &= ~ECHO; 528*27228Sminshall notc2 = ntc; 529*27228Sminshall tc = ¬c2; 530*27228Sminshall noltc2 = oltc; 531*27228Sminshall ltc = &noltc2; 53227110Sminshall /* 53327110Sminshall * If user hasn't specified one way or the other, 53427110Sminshall * then default to trapping signals. 53527110Sminshall */ 536*27228Sminshall if (!donelclsigs) { 53727110Sminshall localsigs = 1; 538*27228Sminshall } 539*27228Sminshall if (localsigs) { 540*27228Sminshall notc2.t_brkc = nltc.t_flushc; 541*27228Sminshall noltc2.t_flushc = -1; 542*27228Sminshall } else { 54327110Sminshall notc2.t_intrc = notc2.t_quitc = -1; 54427110Sminshall } 54527110Sminshall noltc2.t_suspc = escape; 54627110Sminshall noltc2.t_dsuspc = -1; 54727110Sminshall onoff = 1; 54827110Sminshall break; 5499972Ssam 5509972Ssam default: 5519972Ssam return; 5526000Sroot } 55313076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 55413076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 55513076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 55627186Sminshall ioctl(fileno(stdin), FIONBIO, (char *)&onoff); 55727186Sminshall ioctl(fileno(stdout), FIONBIO, (char *)&onoff); 55827110Sminshall if (f >= 3) 55927110Sminshall signal(SIGTSTP, doescape); 56027110Sminshall else if (old >= 3) { 56127110Sminshall signal(SIGTSTP, SIG_DFL); 56227110Sminshall sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 56327110Sminshall } 5646000Sroot } 56527186Sminshall 56627110Sminshall /* 56727110Sminshall * These routines decides on what the mode should be (based on the values 56827110Sminshall * of various global variables). 56927110Sminshall */ 57027110Sminshall 57127178Sminshall char *modedescriptions[] = { 57227178Sminshall "telnet command mode", /* 0 */ 57327178Sminshall "character-at-a-time mode", /* 1 */ 57427178Sminshall "character-at-a-time mode (local echo)", /* 2 */ 57527178Sminshall "line-by-line mode (remote echo)", /* 3 */ 57627178Sminshall "line-by-line mode", /* 4 */ 57727178Sminshall "line-by-line mode (local echoing suppressed)", /* 5 */ 57827178Sminshall }; 57927178Sminshall 58027178Sminshall getconnmode() 58127110Sminshall { 58227110Sminshall static char newmode[8] = { 4, 5, 3, 3, 2, 2, 1, 1 }; 58327186Sminshall int modeindex = 0; 58427110Sminshall 58527110Sminshall if (hisopts[TELOPT_ECHO]) { 58627186Sminshall modeindex += 2; 58727110Sminshall } 58827110Sminshall if (hisopts[TELOPT_SGA]) { 58927186Sminshall modeindex += 4; 59027110Sminshall } 59127186Sminshall if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { 59227186Sminshall modeindex += 1; 59327110Sminshall } 59427186Sminshall return newmode[modeindex]; 59527110Sminshall } 59627110Sminshall 59727178Sminshall setconnmode() 59827178Sminshall { 59927178Sminshall mode(getconnmode()); 60027178Sminshall } 60127110Sminshall 60227178Sminshall 60327110Sminshall setcommandmode() 60427110Sminshall { 60527110Sminshall mode(0); 60627110Sminshall } 60727110Sminshall 6086000Sroot char sibuf[BUFSIZ], *sbp; 6096000Sroot char tibuf[BUFSIZ], *tbp; 6106000Sroot int scc, tcc; 6116000Sroot 612*27228Sminshall 6136000Sroot /* 6146000Sroot * Select from tty and network... 6156000Sroot */ 61627088Sminshall telnet() 6176000Sroot { 6186000Sroot register int c; 61927088Sminshall int tin = fileno(stdin); 6206000Sroot int on = 1; 6216000Sroot 62227088Sminshall tout = fileno(stdout); 62327110Sminshall setconnmode(); 624*27228Sminshall scc = 0; 625*27228Sminshall tcc = 0; 62627186Sminshall ioctl(net, FIONBIO, (char *)&on); 627*27228Sminshall #if defined(xxxSO_OOBINLINE) 628*27228Sminshall setsockopt(net, SOL_SOCKET, SO_OOBINLINE, on, sizeof on); 629*27228Sminshall #endif /* defined(xxxSO_OOBINLINE) */ 63027088Sminshall if (telnetport && !hisopts[TELOPT_SGA]) { 63117922Sralph willoption(TELOPT_SGA); 63227088Sminshall } 6336000Sroot for (;;) { 63427110Sminshall fd_set ibits, obits, xbits; 6356000Sroot 63627110Sminshall if (scc < 0 && tcc < 0) { 6376000Sroot break; 63827110Sminshall } 63927110Sminshall 64027110Sminshall FD_ZERO(&ibits); 64127110Sminshall FD_ZERO(&obits); 64227110Sminshall FD_ZERO(&xbits); 64327110Sminshall 644*27228Sminshall if (((globalmode < 4) || flushline) && NETBYTES()) { 64527110Sminshall FD_SET(net, &obits); 64627088Sminshall } else { 64727110Sminshall FD_SET(tin, &ibits); 64827088Sminshall } 649*27228Sminshall if (TTYBYTES()) { 65027110Sminshall FD_SET(tout, &obits); 65127110Sminshall } else { 65227110Sminshall FD_SET(net, &ibits); 65327110Sminshall } 65427186Sminshall if (!SYNCHing) { 65527110Sminshall FD_SET(net, &xbits); 65627110Sminshall } 65727186Sminshall if ((c = select(16, &ibits, &obits, &xbits, 65827186Sminshall (struct timeval *)0)) < 1) { 65927110Sminshall if (c == -1) { 66027110Sminshall /* 66127110Sminshall * we can get EINTR if we are in line mode, 66227110Sminshall * and the user does an escape (TSTP), or 66327110Sminshall * some other signal generator. 66427110Sminshall */ 66527110Sminshall if (errno == EINTR) { 66627110Sminshall continue; 66727110Sminshall } 66827110Sminshall } 6696000Sroot sleep(5); 6706000Sroot continue; 6716000Sroot } 6726000Sroot 6736000Sroot /* 67427088Sminshall * Any urgent data? 67527088Sminshall */ 67627110Sminshall if (FD_ISSET(net, &xbits)) { 67727186Sminshall SYNCHing = 1; 67827088Sminshall ttyflush(); /* flush already enqueued data */ 67927088Sminshall } 68027088Sminshall 68127088Sminshall /* 6826000Sroot * Something to read from the network... 6836000Sroot */ 68427110Sminshall if (FD_ISSET(net, &ibits)) { 685*27228Sminshall int canread; 686*27228Sminshall 687*27228Sminshall if (scc == 0) { 688*27228Sminshall sbp = sibuf; 689*27228Sminshall } 690*27228Sminshall canread = sibuf + sizeof sibuf - sbp; 691*27228Sminshall #if !defined(xxxSO_OOBINLINE) 69227178Sminshall /* 69327178Sminshall * In 4.2 (and some early 4.3) systems, the 69427178Sminshall * OOB indication and data handling in the kernel 69527178Sminshall * is such that if two separate TCP Urgent requests 69627178Sminshall * come in, one byte of TCP data will be overlaid. 69727178Sminshall * This is fatal for Telnet, but we try to live 69827178Sminshall * with it. 69927178Sminshall * 70027178Sminshall * In addition, in 4.2 (and...), a special protocol 70127178Sminshall * is needed to pick up the TCP Urgent data in 70227178Sminshall * the correct sequence. 70327178Sminshall * 70427178Sminshall * What we do is: if we think we are in urgent 70527178Sminshall * mode, we look to see if we are "at the mark". 70627178Sminshall * If we are, we do an OOB receive. If we run 70727178Sminshall * this twice, we will do the OOB receive twice, 70827178Sminshall * but the second will fail, since the second 70927178Sminshall * time we were "at the mark", but there wasn't 71027178Sminshall * any data there (the kernel doesn't reset 71127178Sminshall * "at the mark" until we do a normal read). 71227178Sminshall * Once we've read the OOB data, we go ahead 71327178Sminshall * and do normal reads. 71427178Sminshall * 71527178Sminshall * There is also another problem, which is that 71627178Sminshall * since the OOB byte we read doesn't put us 71727178Sminshall * out of OOB state, and since that byte is most 71827178Sminshall * likely the TELNET DM (data mark), we would 71927186Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 72027178Sminshall * So, clocks to the rescue. If we've "just" 72127178Sminshall * received a DM, then we test for the 72227178Sminshall * presence of OOB data when the receive OOB 72327178Sminshall * fails (and AFTER we did the normal mode read 72427178Sminshall * to clear "at the mark"). 72527178Sminshall */ 72627186Sminshall if (SYNCHing) { 72727178Sminshall int atmark; 72827178Sminshall 72927186Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 73027178Sminshall if (atmark) { 731*27228Sminshall c = recv(net, sibuf, canread, MSG_OOB); 732*27228Sminshall if ((c == -1) && (errno == EINVAL)) { 733*27228Sminshall c = read(net, sibuf, canread); 73427186Sminshall if (clocks.didnetreceive < clocks.gotDM) { 73527186Sminshall SYNCHing = stilloob(net); 73627021Sminshall } 73727178Sminshall } 73827178Sminshall } else { 739*27228Sminshall c = read(net, sibuf, canread); 7406000Sroot } 74127178Sminshall } else { 742*27228Sminshall c = read(net, sibuf, canread); 74327178Sminshall } 74427178Sminshall settimer(didnetreceive); 745*27228Sminshall #else /* !defined(xxxSO_OOBINLINE) */ 746*27228Sminshall c = read(net, sbp, canread); 747*27228Sminshall #endif /* !defined(xxxSO_OOBINLINE) */ 748*27228Sminshall if (c < 0 && errno == EWOULDBLOCK) { 749*27228Sminshall c = 0; 750*27228Sminshall } else if (c <= 0) { 751*27228Sminshall break; 75227178Sminshall } 753*27228Sminshall if (netdata) { 754*27228Sminshall Dump('<', sbp, c); 755*27228Sminshall } 756*27228Sminshall scc += c; 7576000Sroot } 7586000Sroot 7596000Sroot /* 7606000Sroot * Something to read from the tty... 7616000Sroot */ 76227110Sminshall if (FD_ISSET(tin, &ibits)) { 763*27228Sminshall if (tcc == 0) { 764*27228Sminshall tbp = tibuf; /* nothing left, reset */ 7656000Sroot } 766*27228Sminshall c = read(tin, tbp, tibuf+sizeof tibuf - tbp); 767*27228Sminshall if (c < 0 && errno == EWOULDBLOCK) { 768*27228Sminshall c = 0; 769*27228Sminshall } else if (c <= 0) { 770*27228Sminshall tcc = c; 771*27228Sminshall break; 772*27228Sminshall } 773*27228Sminshall tcc += c; 7746000Sroot } 7756000Sroot 7766000Sroot while (tcc > 0) { 77727186Sminshall register int sc; 7786000Sroot 779*27228Sminshall if (NETROOM() < 2) { 78027110Sminshall flushline = 1; 7816000Sroot break; 78227110Sminshall } 78327186Sminshall c = *tbp++ & 0xff, sc = strip(c), tcc--; 78427186Sminshall if (sc == escape) { 7856000Sroot command(0); 7866000Sroot tcc = 0; 78727110Sminshall flushline = 1; 7886000Sroot break; 78927110Sminshall } else if ((globalmode >= 4) && doechocharrecognition && 79027186Sminshall (sc == echoc)) { 79127110Sminshall if (tcc > 0 && strip(*tbp) == echoc) { 79227110Sminshall tbp++; 79327110Sminshall tcc--; 79427110Sminshall } else { 79527110Sminshall dontlecho = !dontlecho; 79627110Sminshall settimer(echotoggle); 79727110Sminshall setconnmode(); 79827110Sminshall tcc = 0; 79927110Sminshall flushline = 1; 80027110Sminshall break; 80127110Sminshall } 8026000Sroot } 80327110Sminshall if (localsigs) { 80427186Sminshall if (sc == ntc.t_intrc) { 80527110Sminshall intp(); 80627110Sminshall break; 80727186Sminshall } else if (sc == ntc.t_quitc) { 80827110Sminshall sendbrk(); 80927110Sminshall break; 810*27228Sminshall } else if (sc == nltc.t_flushc) { 811*27228Sminshall NET2ADD(IAC, AO); 812*27228Sminshall if (autoflush) { 813*27228Sminshall doflush(); 814*27228Sminshall } 815*27228Sminshall break; 81627110Sminshall } else if (globalmode > 2) { 81727110Sminshall ; 81827186Sminshall } else if (sc == nttyb.sg_kill) { 81927110Sminshall NET2ADD(IAC, EL); 82027110Sminshall break; 82127186Sminshall } else if (sc == nttyb.sg_erase) { 82227110Sminshall NET2ADD(IAC, EC); 82327110Sminshall break; 82427110Sminshall } 82527110Sminshall } 82617922Sralph switch (c) { 82717922Sralph case '\n': 82827021Sminshall /* 82927021Sminshall * If echoing is happening locally, 83027021Sminshall * then a newline (unix) is CRLF (TELNET). 83127021Sminshall */ 83227088Sminshall if (!hisopts[TELOPT_ECHO]) { 83327088Sminshall NETADD('\r'); 83427088Sminshall } 83527088Sminshall NETADD('\n'); 83627110Sminshall flushline = 1; 83717922Sralph break; 83817922Sralph case '\r': 83927088Sminshall NET2ADD('\r', '\0'); 84027110Sminshall flushline = 1; 84117922Sralph break; 84217922Sralph case IAC: 84327088Sminshall NET2ADD(IAC, IAC); 84427021Sminshall break; 84517922Sralph default: 84627088Sminshall NETADD(c); 84717922Sralph break; 84817922Sralph } 8496000Sroot } 85027110Sminshall if (((globalmode < 4) || flushline) && 851*27228Sminshall FD_ISSET(net, &obits) && (NETBYTES() > 0)) { 85227088Sminshall netflush(net); 85327110Sminshall } 8546000Sroot if (scc > 0) 8556000Sroot telrcv(); 856*27228Sminshall if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) 85727088Sminshall ttyflush(); 8586000Sroot } 85927110Sminshall setcommandmode(); 8606000Sroot } 86127110Sminshall 8626000Sroot /* 8636000Sroot * Telnet receiver states for fsm 8646000Sroot */ 8656000Sroot #define TS_DATA 0 8666000Sroot #define TS_IAC 1 8676000Sroot #define TS_WILL 2 8686000Sroot #define TS_WONT 3 8696000Sroot #define TS_DO 4 8706000Sroot #define TS_DONT 5 87127021Sminshall #define TS_CR 6 8726000Sroot 8736000Sroot telrcv() 8746000Sroot { 8756000Sroot register int c; 8766000Sroot static int state = TS_DATA; 8776000Sroot 878*27228Sminshall while ((scc > 0) && (TTYROOM() > 2)) { 87927186Sminshall c = *sbp++ & 0xff, scc--; 8806000Sroot switch (state) { 8816000Sroot 88227021Sminshall case TS_CR: 88327021Sminshall state = TS_DATA; 884*27228Sminshall if (c == '\0') { 885*27228Sminshall break; /* Ignore \0 after CR */ 886*27228Sminshall } else if (c == '\n') { 887*27228Sminshall if (hisopts[TELOPT_ECHO] && !crmod) { 888*27228Sminshall TTYADD(c); 889*27228Sminshall } 890*27228Sminshall break; 89127021Sminshall } 892*27228Sminshall /* Else, fall through */ 89327021Sminshall 8946000Sroot case TS_DATA: 8959972Ssam if (c == IAC) { 8966000Sroot state = TS_IAC; 8979972Ssam continue; 8989972Ssam } 899*27228Sminshall /* 900*27228Sminshall * The 'crmod' hack (see following) is needed 901*27228Sminshall * since we can't * set CRMOD on output only. 902*27228Sminshall * Machines like MULTICS like to send \r without 903*27228Sminshall * \n; since we must turn off CRMOD to get proper 904*27228Sminshall * input, the mapping is done here (sigh). 905*27228Sminshall */ 90627021Sminshall if (c == '\r') { 90727021Sminshall if (scc > 0) { 90827186Sminshall c = *sbp&0xff; 90927021Sminshall if (c == 0) { 91027021Sminshall sbp++, scc--; 911*27228Sminshall /* a "true" CR */ 91227088Sminshall TTYADD('\r'); 91327021Sminshall } else if (!hisopts[TELOPT_ECHO] && 91427021Sminshall (c == '\n')) { 91527021Sminshall sbp++, scc--; 91627088Sminshall TTYADD('\n'); 91727021Sminshall } else { 91827088Sminshall TTYADD('\r'); 919*27228Sminshall if (crmod) { 920*27228Sminshall TTYADD('\n'); 921*27228Sminshall } 92227021Sminshall } 92327021Sminshall } else { 92427021Sminshall state = TS_CR; 92527088Sminshall TTYADD('\r'); 926*27228Sminshall if (crmod) { 927*27228Sminshall TTYADD('\n'); 928*27228Sminshall } 92927021Sminshall } 93027021Sminshall } else { 93127088Sminshall TTYADD(c); 93227021Sminshall } 9336000Sroot continue; 9346000Sroot 9356000Sroot case TS_IAC: 9366000Sroot switch (c) { 9376000Sroot 9386000Sroot case WILL: 9396000Sroot state = TS_WILL; 9406000Sroot continue; 9416000Sroot 9426000Sroot case WONT: 9436000Sroot state = TS_WONT; 9446000Sroot continue; 9456000Sroot 9466000Sroot case DO: 9476000Sroot state = TS_DO; 9486000Sroot continue; 9496000Sroot 9506000Sroot case DONT: 9516000Sroot state = TS_DONT; 9526000Sroot continue; 9536000Sroot 9546000Sroot case DM: 95527088Sminshall /* 95627088Sminshall * We may have missed an urgent notification, 95727088Sminshall * so make sure we flush whatever is in the 95827088Sminshall * buffer currently. 95927088Sminshall */ 96027186Sminshall SYNCHing = 1; 96127088Sminshall ttyflush(); 96227186Sminshall SYNCHing = stilloob(net); 96327178Sminshall settimer(gotDM); 9646000Sroot break; 9656000Sroot 9666000Sroot case NOP: 9676000Sroot case GA: 9686000Sroot break; 9696000Sroot 9706000Sroot default: 9716000Sroot break; 9726000Sroot } 9736000Sroot state = TS_DATA; 9746000Sroot continue; 9756000Sroot 9766000Sroot case TS_WILL: 9778345Ssam printoption("RCVD", will, c, !hisopts[c]); 97827110Sminshall if (c == TELOPT_TM) { 97927110Sminshall if (flushout) { 98027186Sminshall flushout = 0; 98127110Sminshall } 98227110Sminshall } else if (!hisopts[c]) { 9836000Sroot willoption(c); 98427110Sminshall } 9856000Sroot state = TS_DATA; 9866000Sroot continue; 9876000Sroot 9886000Sroot case TS_WONT: 9898345Ssam printoption("RCVD", wont, c, hisopts[c]); 99027110Sminshall if (c == TELOPT_TM) { 99127110Sminshall if (flushout) { 99227186Sminshall flushout = 0; 99327110Sminshall } 99427110Sminshall } else if (hisopts[c]) { 9956000Sroot wontoption(c); 99627110Sminshall } 9976000Sroot state = TS_DATA; 9986000Sroot continue; 9996000Sroot 10006000Sroot case TS_DO: 10018345Ssam printoption("RCVD", doopt, c, !myopts[c]); 10026000Sroot if (!myopts[c]) 10036000Sroot dooption(c); 10046000Sroot state = TS_DATA; 10056000Sroot continue; 10066000Sroot 10076000Sroot case TS_DONT: 10088345Ssam printoption("RCVD", dont, c, myopts[c]); 10096000Sroot if (myopts[c]) { 10106000Sroot myopts[c] = 0; 10116000Sroot sprintf(nfrontp, wont, c); 10128378Ssam nfrontp += sizeof (wont) - 2; 101327110Sminshall flushline = 1; 101427110Sminshall setconnmode(); /* set new tty mode (maybe) */ 10158345Ssam printoption("SENT", wont, c); 10166000Sroot } 10176000Sroot state = TS_DATA; 10186000Sroot continue; 10196000Sroot } 10206000Sroot } 10216000Sroot } 102227110Sminshall 10236000Sroot willoption(option) 10246000Sroot int option; 10256000Sroot { 10266000Sroot char *fmt; 10276000Sroot 10286000Sroot switch (option) { 10296000Sroot 10306000Sroot case TELOPT_ECHO: 10316000Sroot case TELOPT_SGA: 103227110Sminshall settimer(modenegotiated); 10336000Sroot hisopts[option] = 1; 10346000Sroot fmt = doopt; 103527110Sminshall setconnmode(); /* possibly set new tty mode */ 10366000Sroot break; 10376000Sroot 10386000Sroot case TELOPT_TM: 103927110Sminshall return; /* Never reply to TM will's/wont's */ 10406000Sroot 10416000Sroot default: 10426000Sroot fmt = dont; 10436000Sroot break; 10446000Sroot } 10456024Ssam sprintf(nfrontp, fmt, option); 10468378Ssam nfrontp += sizeof (dont) - 2; 10478345Ssam printoption("SENT", fmt, option); 10486000Sroot } 10496000Sroot 10506000Sroot wontoption(option) 10516000Sroot int option; 10526000Sroot { 10536000Sroot char *fmt; 10546000Sroot 10556000Sroot switch (option) { 10566000Sroot 10576000Sroot case TELOPT_ECHO: 10586000Sroot case TELOPT_SGA: 105927110Sminshall settimer(modenegotiated); 10606000Sroot hisopts[option] = 0; 10616000Sroot fmt = dont; 106227110Sminshall setconnmode(); /* Set new tty mode */ 10636000Sroot break; 10646000Sroot 106527110Sminshall case TELOPT_TM: 106627110Sminshall return; /* Never reply to TM will's/wont's */ 106727110Sminshall 10686000Sroot default: 10696000Sroot fmt = dont; 10706000Sroot } 10716000Sroot sprintf(nfrontp, fmt, option); 10728378Ssam nfrontp += sizeof (doopt) - 2; 10738345Ssam printoption("SENT", fmt, option); 10746000Sroot } 10756000Sroot 10766000Sroot dooption(option) 10776000Sroot int option; 10786000Sroot { 10796000Sroot char *fmt; 10806000Sroot 10816000Sroot switch (option) { 10826000Sroot 10836000Sroot case TELOPT_TM: 108413231Ssam fmt = will; 108513231Ssam break; 108613231Ssam 108727110Sminshall case TELOPT_SGA: /* no big deal */ 10886000Sroot fmt = will; 108927110Sminshall myopts[option] = 1; 10906000Sroot break; 10916000Sroot 109227110Sminshall case TELOPT_ECHO: /* We're never going to echo... */ 10936000Sroot default: 10946000Sroot fmt = wont; 10956000Sroot break; 10966000Sroot } 10976000Sroot sprintf(nfrontp, fmt, option); 10988378Ssam nfrontp += sizeof (doopt) - 2; 10998345Ssam printoption("SENT", fmt, option); 11006000Sroot } 110127110Sminshall 11026000Sroot /* 110327088Sminshall * The following are data structures and routines for 110427088Sminshall * the "send" command. 110527088Sminshall * 110627088Sminshall */ 110727088Sminshall 110827088Sminshall struct sendlist { 110927088Sminshall char *name; /* How user refers to it (case independent) */ 111027088Sminshall int what; /* Character to be sent (<0 ==> special) */ 111127088Sminshall char *help; /* Help information (0 ==> no help) */ 111227088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 111327088Sminshall }; 111427088Sminshall 111527186Sminshall /*ARGSUSED*/ 111627088Sminshall dosynch(s) 111727088Sminshall struct sendlist *s; 111827088Sminshall { 111927088Sminshall /* XXX We really should purge the buffer to the network */ 112027088Sminshall NET2ADD(IAC, DM); 112127186Sminshall neturg = NETLOC()-1; /* Some systems are off by one XXX */ 112227088Sminshall } 112327088Sminshall 1124*27228Sminshall doflush() 1125*27228Sminshall { 1126*27228Sminshall /* This shouldn't really be here... */ 1127*27228Sminshall NET2ADD(IAC, DO); 1128*27228Sminshall NETADD(TELOPT_TM); 1129*27228Sminshall printoption("SENT", doopt, TELOPT_TM); 1130*27228Sminshall flushline = 1; 1131*27228Sminshall flushout = 1; 1132*27228Sminshall ttyflush(); 1133*27228Sminshall } 1134*27228Sminshall 113527088Sminshall intp() 113627088Sminshall { 113727110Sminshall NET2ADD(IAC, IP); 1138*27228Sminshall if (autoflush) { 1139*27228Sminshall doflush(); 1140*27228Sminshall } 1141*27228Sminshall if (autosynch) { 1142*27228Sminshall dosynch(); 1143*27228Sminshall } 114427088Sminshall } 114527088Sminshall 114627110Sminshall sendbrk() 114727110Sminshall { 114827186Sminshall NET2ADD(IAC, BREAK); 1149*27228Sminshall if (autoflush) { 1150*27228Sminshall doflush(); 1151*27228Sminshall } 1152*27228Sminshall if (autosynch) { 1153*27228Sminshall dosynch(); 1154*27228Sminshall } 115527110Sminshall } 115627088Sminshall 115727110Sminshall 115827088Sminshall #define SENDQUESTION -1 115927088Sminshall #define SEND2QUESTION -2 116027088Sminshall #define SENDESCAPE -3 116127088Sminshall 116227088Sminshall struct sendlist Sendlist[] = { 116327088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 116427088Sminshall { "brk", BREAK, "Send Telnet Break" }, 116527088Sminshall { "break", BREAK, 0 }, 116627088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 116727088Sminshall { "intp", IP, 0 }, 116827088Sminshall { "interrupt", IP, 0 }, 116927088Sminshall { "intr", IP, 0 }, 117027088Sminshall { "ao", AO, "Send Telnet Abort output" }, 117127088Sminshall { "abort", AO, 0 }, 117227088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 117327088Sminshall { "are", AYT, 0 }, 117427088Sminshall { "hello", AYT, 0 }, 117527088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 117627088Sminshall { "el", EL, "Send Telnet Erase Line" }, 117727088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 117827088Sminshall { "go", GA, 0 }, 117927088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 118027088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 118127088Sminshall { "?", SENDQUESTION, "Display send options" }, 118227088Sminshall { "help", SENDQUESTION, 0 }, 118327088Sminshall { "??", SEND2QUESTION, "Display all send options (including aliases)" }, 118427088Sminshall { 0 } 118527088Sminshall }; 118627088Sminshall 118727088Sminshall char ** 118827088Sminshall getnextsend(name) 118927088Sminshall char *name; 119027088Sminshall { 119127088Sminshall struct sendlist *c = (struct sendlist *) name; 119227088Sminshall 119327088Sminshall return (char **) (c+1); 119427088Sminshall } 119527088Sminshall 119627088Sminshall struct sendlist * 119727088Sminshall getsend(name) 119827088Sminshall char *name; 119927088Sminshall { 120027088Sminshall return (struct sendlist *) genget(name, (char **) Sendlist, getnextsend); 120127088Sminshall } 120227088Sminshall 120327088Sminshall sendcmd(argc, argv) 120427088Sminshall int argc; 120527088Sminshall char **argv; 120627088Sminshall { 120727088Sminshall int what; /* what we are sending this time */ 120827088Sminshall int count; /* how many bytes we are going to need to send */ 120927088Sminshall int hadsynch; /* are we going to process a "synch"? */ 121027088Sminshall int i; 121127088Sminshall struct sendlist *s; /* pointer to current command */ 121227088Sminshall 121327088Sminshall if (argc < 2) { 121427088Sminshall printf("need at least one argument for 'send' command\n"); 121527088Sminshall printf("'send ?' for help\n"); 121627088Sminshall return; 121727088Sminshall } 121827088Sminshall /* 121927088Sminshall * First, validate all the send arguments. 122027088Sminshall * In addition, we see how much space we are going to need, and 122127088Sminshall * whether or not we will be doing a "SYNCH" operation (which 122227088Sminshall * flushes the network queue). 122327088Sminshall */ 122427088Sminshall count = 0; 122527088Sminshall hadsynch = 0; 122627088Sminshall for (i = 1; i < argc; i++) { 122727088Sminshall s = getsend(argv[i]); 122827088Sminshall if (s == 0) { 122927088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 123027088Sminshall argv[i]); 123127088Sminshall return; 123227186Sminshall } else if (s == Ambiguous(struct sendlist *)) { 123327088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 123427088Sminshall argv[i]); 123527088Sminshall return; 123627088Sminshall } 123727088Sminshall switch (s->what) { 123827088Sminshall case SENDQUESTION: 123927088Sminshall case SEND2QUESTION: 124027088Sminshall break; 124127088Sminshall case SENDESCAPE: 124227088Sminshall count += 1; 124327088Sminshall break; 124427088Sminshall case SYNCH: 124527088Sminshall hadsynch = 1; 124627088Sminshall count += 2; 124727088Sminshall break; 124827088Sminshall default: 124927088Sminshall count += 2; 125027088Sminshall break; 125127088Sminshall } 125227088Sminshall } 125327088Sminshall /* Now, do we have enough room? */ 1254*27228Sminshall if (NETROOM() < count) { 125527088Sminshall printf("There is not enough room in the buffer TO the network\n"); 125627088Sminshall printf("to process your request. Nothing will be done.\n"); 125727088Sminshall printf("('send synch' will throw away most data in the network\n"); 125827088Sminshall printf("buffer, if this might help.)\n"); 125927088Sminshall return; 126027088Sminshall } 126127088Sminshall /* OK, they are all OK, now go through again and actually send */ 126227088Sminshall for (i = 1; i < argc; i++) { 126327088Sminshall if (!(s = getsend(argv[i]))) { 126427088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 126527088Sminshall quit(); 126627088Sminshall /*NOTREACHED*/ 126727088Sminshall } 126827088Sminshall if (s->routine) { 126927088Sminshall (*s->routine)(s); 127027088Sminshall } else { 127127088Sminshall switch (what = s->what) { 127227088Sminshall case SENDQUESTION: 127327088Sminshall case SEND2QUESTION: 127427088Sminshall for (s = Sendlist; s->name; s++) { 127527088Sminshall if (s->help || (what == SEND2QUESTION)) { 127627088Sminshall printf(s->name); 127727088Sminshall if (s->help) { 127827088Sminshall printf("\t%s", s->help); 127927088Sminshall } 128027088Sminshall printf("\n"); 128127088Sminshall } 128227088Sminshall } 128327088Sminshall break; 128427088Sminshall case SENDESCAPE: 128527088Sminshall NETADD(escape); 128627088Sminshall break; 128727088Sminshall default: 128827088Sminshall NET2ADD(IAC, what); 128927088Sminshall break; 129027088Sminshall } 129127088Sminshall } 129227088Sminshall } 129327088Sminshall } 129427088Sminshall 129527088Sminshall /* 129627088Sminshall * The following are the routines and data structures referred 129727088Sminshall * to by the arguments to the "toggle" command. 129827088Sminshall */ 129927088Sminshall 130027110Sminshall lclsigs() 130127110Sminshall { 130227110Sminshall donelclsigs = 1; 130327110Sminshall } 130427110Sminshall 130527110Sminshall /*VARARGS*/ 130627178Sminshall togcrmod() 130727110Sminshall { 130827110Sminshall crmod = !crmod; 130927186Sminshall printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 131027110Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 131127110Sminshall fflush(stdout); 131227110Sminshall } 131327110Sminshall 131427178Sminshall togdebug() 131527088Sminshall { 131627110Sminshall if (net > 0 && 131727186Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug)) 131827186Sminshall < 0) { 131927110Sminshall perror("setsockopt (SO_DEBUG)"); 132027186Sminshall } 132127088Sminshall } 132227088Sminshall 132327088Sminshall 132427088Sminshall 132527088Sminshall int togglehelp(); 132627088Sminshall 132727110Sminshall char crmodhelp[] = "toggle mapping of received carriage returns"; 132827110Sminshall 132927178Sminshall struct togglelist { 133027178Sminshall char *name; /* name of toggle */ 133127178Sminshall char *help; /* help message */ 133227186Sminshall int (*handler)(); /* routine to do actual setting */ 133327178Sminshall int dohelp; /* should we display help information */ 133427178Sminshall int *variable; 133527178Sminshall char *actionexplanation; 133627178Sminshall }; 133727178Sminshall 133827178Sminshall struct togglelist Togglelist[] = { 133927178Sminshall { "localchars", 134027178Sminshall "toggle local recognition of control characters", 134127178Sminshall lclsigs, 134227178Sminshall 1, 134327178Sminshall &localsigs, 134427178Sminshall "recognize interrupt/quit characters" }, 134527178Sminshall { "echochar", 134627178Sminshall "toggle recognition of echo toggle character", 134727186Sminshall 0, 134827178Sminshall 1, 134927178Sminshall &doechocharrecognition, 135027178Sminshall "recognize echo toggle character" }, 135127186Sminshall { "autosynch", 135227186Sminshall "toggle automatic sending of interrupt characters in urgent mode", 135327186Sminshall 0, 135427186Sminshall 1, 135527186Sminshall &autosynch, 135627186Sminshall "send interrupt characters in urgent mode" }, 1357*27228Sminshall { "autoflush", 1358*27228Sminshall "toggle automatic flushing of output when sending interrupt characters", 1359*27228Sminshall 0, 1360*27228Sminshall 1, 1361*27228Sminshall &autoflush, 1362*27228Sminshall "flush output when sending interrupt characters" }, 136327178Sminshall { "crmod", 136427178Sminshall crmodhelp, 136527186Sminshall 0, 136627178Sminshall 1, 136727178Sminshall &crmod, 136827178Sminshall "map carriage return on output" }, 136927110Sminshall { " ", "", 0, 1 }, /* empty line */ 137027178Sminshall { "debug", 137127178Sminshall "(debugging) toggle debugging", 137227178Sminshall togdebug, 137327178Sminshall 1, 137427178Sminshall &debug, 137527178Sminshall "turn on socket level debugging" }, 137627178Sminshall { "options", 137727178Sminshall "(debugging) toggle viewing of options processing", 137827186Sminshall 0, 137927178Sminshall 1, 138027178Sminshall &showoptions, 138127178Sminshall "show option processing" }, 138227178Sminshall { "netdata", 138327178Sminshall "(debugging) toggle printing of hexadecimal network data", 138427186Sminshall 0, 138527178Sminshall 1, 138627178Sminshall &netdata, 138727178Sminshall "print hexadecimal representation of network traffic" }, 138827178Sminshall { "?", 138927178Sminshall "display help information", 139027178Sminshall togglehelp, 139127178Sminshall 1 }, 139227178Sminshall { "help", 139327178Sminshall "display help information", 139427178Sminshall togglehelp, 139527178Sminshall 0 }, 139627088Sminshall { 0 } 139727088Sminshall }; 139827088Sminshall 139927088Sminshall togglehelp() 140027088Sminshall { 140127178Sminshall struct togglelist *c; 140227088Sminshall 140327178Sminshall for (c = Togglelist; c->name; c++) { 140427088Sminshall if (c->dohelp) { 140527088Sminshall printf("%s\t%s\n", c->name, c->help); 140627088Sminshall } 140727088Sminshall } 140827088Sminshall } 140927088Sminshall 141027088Sminshall char ** 141127088Sminshall getnexttoggle(name) 141227088Sminshall char *name; 141327088Sminshall { 141427178Sminshall struct togglelist *c = (struct togglelist *) name; 141527088Sminshall 141627088Sminshall return (char **) (c+1); 141727088Sminshall } 141827088Sminshall 141927178Sminshall struct togglelist * 142027088Sminshall gettoggle(name) 142127088Sminshall char *name; 142227088Sminshall { 142327178Sminshall return (struct togglelist *) 142427178Sminshall genget(name, (char **) Togglelist, getnexttoggle); 142527088Sminshall } 142627088Sminshall 142727088Sminshall toggle(argc, argv) 142827088Sminshall int argc; 142927088Sminshall char *argv[]; 143027088Sminshall { 143127088Sminshall char *name; 143227178Sminshall struct togglelist *c; 143327088Sminshall 143427088Sminshall if (argc < 2) { 143527088Sminshall fprintf(stderr, 143627088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 143727088Sminshall return; 143827088Sminshall } 143927088Sminshall argc--; 144027088Sminshall argv++; 144127088Sminshall while (argc--) { 144227088Sminshall name = *argv++; 144327088Sminshall c = gettoggle(name); 144427186Sminshall if (c == Ambiguous(struct togglelist *)) { 144527088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 144627088Sminshall name); 144727088Sminshall } else if (c == 0) { 144827088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 144927088Sminshall name); 145027088Sminshall } else { 145127186Sminshall if (c->variable) { 145227186Sminshall *c->variable = !*c->variable; /* invert it */ 145327186Sminshall printf("%s %s.\n", *c->variable? "Will" : "Won't", 145427186Sminshall c->actionexplanation); 145527186Sminshall } 145627186Sminshall if (c->handler) { 145727186Sminshall (*c->handler)(c); 145827186Sminshall } 145927088Sminshall } 146027088Sminshall } 146127088Sminshall } 146227088Sminshall 146327088Sminshall /* 146427110Sminshall * The following perform the "set" command. 146527110Sminshall */ 146627110Sminshall 146727178Sminshall struct setlist { 146827178Sminshall char *name; /* name */ 146927110Sminshall char *help; /* help information */ 147027110Sminshall char *charp; /* where it is located at */ 147127110Sminshall }; 147227110Sminshall 147327178Sminshall struct setlist Setlist[] = { 147427110Sminshall { "echo", "character to toggle local echoing on/off", &echoc }, 147527110Sminshall { "escape", "character to escape back to telnet command mode", &escape }, 1476*27228Sminshall { "\200", "" }, 1477*27228Sminshall { "\200", "The following need 'localsigs' to be toggled true", 0 }, 147827110Sminshall { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc }, 147927110Sminshall { "quit", "character to cause a Break", &ntc.t_quitc }, 1480*27228Sminshall { "flush output", "character to cause an Abort Oubput", &nltc.t_flushc }, 148127110Sminshall { "erase", "character to cause an Erase Character", &nttyb.sg_erase }, 148227110Sminshall { "kill", "character to cause an Erase Line", &nttyb.sg_kill }, 148327110Sminshall { 0 } 148427110Sminshall }; 148527110Sminshall 148627110Sminshall char ** 148727178Sminshall getnextset(name) 148827110Sminshall char *name; 148927110Sminshall { 149027178Sminshall struct setlist *c = (struct setlist *)name; 149127110Sminshall 149227110Sminshall return (char **) (c+1); 149327110Sminshall } 149427110Sminshall 149527178Sminshall struct setlist * 149627178Sminshall getset(name) 149727110Sminshall char *name; 149827110Sminshall { 149927178Sminshall return (struct setlist *) genget(name, (char **) Setlist, getnextset); 150027110Sminshall } 150127110Sminshall 150227110Sminshall setcmd(argc, argv) 150327110Sminshall int argc; 150427110Sminshall char *argv[]; 150527110Sminshall { 150627110Sminshall int value; 150727178Sminshall struct setlist *ct; 150827110Sminshall 150927110Sminshall /* XXX back we go... sigh */ 151027110Sminshall if (argc != 3) { 151127110Sminshall printf("Format is 'set Name Value', where 'Name' is one of:\n\n"); 151227178Sminshall for (ct = Setlist; ct->name; ct++) { 151327178Sminshall printf("%s\t%s\n", ct->name, ct->help); 151427110Sminshall } 151527110Sminshall return; 151627110Sminshall } 151727110Sminshall 151827178Sminshall ct = getset(argv[1]); 151927110Sminshall if (ct == 0) { 152027110Sminshall fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", 152127110Sminshall argv[1]); 152227186Sminshall } else if (ct == Ambiguous(struct setlist *)) { 152327110Sminshall fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", 152427110Sminshall argv[1]); 152527110Sminshall } else { 152627110Sminshall if (strcmp("off", argv[2])) { 152727110Sminshall value = special(argv[2]); 152827110Sminshall } else { 152927110Sminshall value = -1; 153027110Sminshall } 153127110Sminshall *(ct->charp) = value; 153227178Sminshall printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 153327110Sminshall } 153427110Sminshall } 153527110Sminshall 153627110Sminshall /* 153727110Sminshall * The following are the data structures and routines for the 153827110Sminshall * 'mode' command. 153927110Sminshall */ 154027110Sminshall 154127110Sminshall dolinemode() 154227110Sminshall { 154327110Sminshall if (hisopts[TELOPT_SGA]) { 154427186Sminshall wontoption(TELOPT_SGA); 154527110Sminshall } 154627110Sminshall if (hisopts[TELOPT_ECHO]) { 154727186Sminshall wontoption(TELOPT_ECHO); 154827110Sminshall } 154927110Sminshall } 155027110Sminshall 155127110Sminshall docharmode() 155227110Sminshall { 155327110Sminshall if (!hisopts[TELOPT_SGA]) { 155427186Sminshall willoption(TELOPT_SGA); 155527110Sminshall } 155627110Sminshall if (!hisopts[TELOPT_ECHO]) { 155727186Sminshall willoption(TELOPT_ECHO); 155827110Sminshall } 155927110Sminshall } 156027110Sminshall 156127110Sminshall struct cmd Modelist[] = { 156227110Sminshall { "line", "line-by-line mode", dolinemode, 1, 1 }, 156327110Sminshall { "character", "character-at-a-time mode", docharmode, 1, 1 }, 156427110Sminshall { 0 }, 156527110Sminshall }; 156627110Sminshall 156727110Sminshall char ** 156827110Sminshall getnextmode(name) 156927110Sminshall char *name; 157027110Sminshall { 157127110Sminshall struct cmd *c = (struct cmd *) name; 157227110Sminshall 157327110Sminshall return (char **) (c+1); 157427110Sminshall } 157527110Sminshall 157627110Sminshall struct cmd * 157727110Sminshall getmodecmd(name) 157827110Sminshall char *name; 157927110Sminshall { 158027110Sminshall return (struct cmd *) genget(name, (char **) Modelist, getnextmode); 158127110Sminshall } 158227110Sminshall 158327110Sminshall modecmd(argc, argv) 158427110Sminshall int argc; 158527110Sminshall char *argv[]; 158627110Sminshall { 158727110Sminshall struct cmd *mt; 158827110Sminshall 158927110Sminshall if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) { 159027110Sminshall printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 159127110Sminshall for (mt = Modelist; mt->name; mt++) { 159227110Sminshall printf("%s\t%s\n", mt->name, mt->help); 159327110Sminshall } 159427110Sminshall return; 159527110Sminshall } 159627110Sminshall mt = getmodecmd(argv[1]); 159727110Sminshall if (mt == 0) { 159827110Sminshall fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 159927186Sminshall } else if (mt == Ambiguous(struct cmd *)) { 160027110Sminshall fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 160127110Sminshall } else { 160227110Sminshall (*mt->handler)(); 160327110Sminshall } 160427110Sminshall } 160527110Sminshall 160627110Sminshall /* 160727178Sminshall * The following data structures and routines implement the 160827178Sminshall * "display" command. 160927178Sminshall */ 161027178Sminshall 161127178Sminshall display(argc, argv) 161227178Sminshall int argc; 161327178Sminshall char *argv[]; 161427178Sminshall { 161527178Sminshall #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 161627178Sminshall if (*tl->variable) { \ 161727178Sminshall printf("will"); \ 161827178Sminshall } else { \ 161927178Sminshall printf("won't"); \ 162027178Sminshall } \ 162127178Sminshall printf(" %s.\n", tl->actionexplanation); \ 162227178Sminshall } 162327178Sminshall 162427178Sminshall #define doset(sl) printf("[%s]\t%s.\n", control(*sl->charp), sl->name); 162527178Sminshall 162627178Sminshall struct togglelist *tl; 162727178Sminshall struct setlist *sl; 162827178Sminshall 162927178Sminshall if (argc == 1) { 163027178Sminshall for (tl = Togglelist; tl->name; tl++) { 163127178Sminshall dotog(tl); 163227178Sminshall } 163327178Sminshall for (sl = Setlist; sl->name; sl++) { 163427178Sminshall doset(sl); 163527178Sminshall } 163627178Sminshall } else { 163727178Sminshall int i; 163827178Sminshall 163927178Sminshall for (i = 1; i < argc; i++) { 164027178Sminshall sl = getset(argv[i]); 164127178Sminshall tl = gettoggle(argv[i]); 164227186Sminshall if ((sl == Ambiguous(struct setlist *)) || 164327186Sminshall (tl == Ambiguous(struct togglelist *))) { 164427178Sminshall printf("?Ambiguous argument '%s'.\n", argv[i]); 164527178Sminshall } else if (!sl && !tl) { 164627178Sminshall printf("?Unknown argument '%s'.\n", argv[i]); 164727178Sminshall } else { 164827186Sminshall if (tl) { 164927186Sminshall dotog(tl); 165027186Sminshall } 165127186Sminshall if (sl) { 165227186Sminshall doset(sl); 165327186Sminshall } 165427178Sminshall } 165527178Sminshall } 165627178Sminshall } 165727178Sminshall #undef doset(sl) 165827178Sminshall #undef dotog(tl) 165927178Sminshall } 166027178Sminshall 166127178Sminshall /* 166227088Sminshall * The following are the data structures, and many of the routines, 166327088Sminshall * relating to command processing. 166427088Sminshall */ 166527088Sminshall 166627088Sminshall /* 166727088Sminshall * Set the escape character. 166827088Sminshall */ 166927088Sminshall setescape(argc, argv) 167027088Sminshall int argc; 167127088Sminshall char *argv[]; 167227088Sminshall { 167327088Sminshall register char *arg; 167427088Sminshall char buf[50]; 167527088Sminshall 167627186Sminshall printf( 167727186Sminshall "Deprecated usage - please use 'set escape%s%s' in the future.\n", 167827186Sminshall (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 167927088Sminshall if (argc > 2) 168027088Sminshall arg = argv[1]; 168127088Sminshall else { 168227088Sminshall printf("new escape character: "); 168327088Sminshall gets(buf); 168427088Sminshall arg = buf; 168527088Sminshall } 168627088Sminshall if (arg[0] != '\0') 168727088Sminshall escape = arg[0]; 168827088Sminshall printf("Escape character is '%s'.\n", control(escape)); 168927088Sminshall fflush(stdout); 169027088Sminshall } 169127088Sminshall 169227088Sminshall /*VARARGS*/ 169327088Sminshall suspend() 169427088Sminshall { 169527110Sminshall setcommandmode(); 169627088Sminshall kill(0, SIGTSTP); 169727088Sminshall /* reget parameters in case they were changed */ 169827088Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 169927088Sminshall ioctl(0, TIOCGETC, (char *)&otc); 170027088Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 170127088Sminshall } 170227088Sminshall 170327088Sminshall /*VARARGS*/ 170427088Sminshall bye() 170527088Sminshall { 170627088Sminshall register char *op; 170727088Sminshall 170827088Sminshall if (connected) { 170927088Sminshall shutdown(net, 2); 171027088Sminshall printf("Connection closed.\n"); 171127088Sminshall close(net); 171227088Sminshall connected = 0; 171327088Sminshall /* reset his options */ 171427088Sminshall for (op = hisopts; op < &hisopts[256]; op++) 171527088Sminshall *op = 0; 171627088Sminshall } 171727088Sminshall } 171827088Sminshall 171927088Sminshall /*VARARGS*/ 172027088Sminshall quit() 172127088Sminshall { 172227088Sminshall call(bye, "bye", 0); 172327088Sminshall exit(0); 172427088Sminshall } 172527088Sminshall 172627088Sminshall /* 172727088Sminshall * Print status about the connection. 172827088Sminshall */ 172927186Sminshall /*ARGSUSED*/ 173027178Sminshall status(argc, argv) 173127178Sminshall int argc; 173227178Sminshall char *argv[]; 173327088Sminshall { 173427178Sminshall if (connected) { 173527178Sminshall printf("Connected to %s.\n", hostname); 173627178Sminshall if (argc < 2) { 173727178Sminshall printf("Operating in %s.\n", modedescriptions[getconnmode()]); 1738*27228Sminshall if (localsigs) { 173927178Sminshall printf("Catching signals locally.\n"); 174027178Sminshall } 174127110Sminshall } 174227178Sminshall } else { 174327178Sminshall printf("No connection.\n"); 174427178Sminshall } 174527178Sminshall printf("Escape character is '%s'.\n", control(escape)); 174627178Sminshall fflush(stdout); 174727088Sminshall } 174827088Sminshall 174927088Sminshall tn(argc, argv) 175027088Sminshall int argc; 175127088Sminshall char *argv[]; 175227088Sminshall { 175327088Sminshall register struct hostent *host = 0; 175427088Sminshall 175527088Sminshall if (connected) { 175627088Sminshall printf("?Already connected to %s\n", hostname); 175727088Sminshall return; 175827088Sminshall } 175927088Sminshall if (argc < 2) { 176027186Sminshall (void) strcpy(line, "Connect "); 176127088Sminshall printf("(to) "); 176227088Sminshall gets(&line[strlen(line)]); 176327088Sminshall makeargv(); 176427088Sminshall argc = margc; 176527088Sminshall argv = margv; 176627088Sminshall } 176727088Sminshall if (argc > 3) { 176827088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 176927088Sminshall return; 177027088Sminshall } 177127088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 177227088Sminshall if (sin.sin_addr.s_addr != -1) { 177327088Sminshall sin.sin_family = AF_INET; 177427186Sminshall (void) strcpy(hnamebuf, argv[1]); 177527088Sminshall hostname = hnamebuf; 177627088Sminshall } else { 177727088Sminshall host = gethostbyname(argv[1]); 177827088Sminshall if (host) { 177927088Sminshall sin.sin_family = host->h_addrtype; 178027088Sminshall bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 178127088Sminshall host->h_length); 178227088Sminshall hostname = host->h_name; 178327088Sminshall } else { 178427088Sminshall printf("%s: unknown host\n", argv[1]); 178527088Sminshall return; 178627088Sminshall } 178727088Sminshall } 178827088Sminshall sin.sin_port = sp->s_port; 178927088Sminshall if (argc == 3) { 179027088Sminshall sin.sin_port = atoi(argv[2]); 179127186Sminshall if (sin.sin_port == 0) { 179227088Sminshall sp = getservbyname(argv[2], "tcp"); 179327088Sminshall if (sp) 179427088Sminshall sin.sin_port = sp->s_port; 179527088Sminshall else { 179627088Sminshall printf("%s: bad port number\n", argv[2]); 179727088Sminshall return; 179827088Sminshall } 179927088Sminshall } else { 180027088Sminshall sin.sin_port = atoi(argv[2]); 180127088Sminshall sin.sin_port = htons(sin.sin_port); 180227088Sminshall } 180327088Sminshall telnetport = 0; 180427110Sminshall } else { 180527110Sminshall telnetport = 1; 180627088Sminshall } 180727088Sminshall signal(SIGINT, intr); 180827110Sminshall signal(SIGQUIT, intr2); 180927088Sminshall signal(SIGPIPE, deadpeer); 181027088Sminshall printf("Trying...\n"); 181127088Sminshall do { 181227088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 181327088Sminshall if (net < 0) { 181427088Sminshall perror("telnet: socket"); 181527088Sminshall return; 181627088Sminshall } 181727186Sminshall if (debug && 181827186Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, 181927186Sminshall (char *)&debug, sizeof(debug)) < 0) { 182027088Sminshall perror("setsockopt (SO_DEBUG)"); 182127186Sminshall } 182227186Sminshall if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 182327088Sminshall if (host && host->h_addr_list[1]) { 182427088Sminshall int oerrno = errno; 182527088Sminshall 182627088Sminshall fprintf(stderr, 182727088Sminshall "telnet: connect to address %s: ", 182827088Sminshall inet_ntoa(sin.sin_addr)); 182927088Sminshall errno = oerrno; 183027186Sminshall perror((char *)0); 183127088Sminshall host->h_addr_list++; 183227088Sminshall bcopy(host->h_addr_list[0], 183327088Sminshall (caddr_t)&sin.sin_addr, host->h_length); 183427088Sminshall fprintf(stderr, "Trying %s...\n", 183527088Sminshall inet_ntoa(sin.sin_addr)); 183627088Sminshall (void) close(net); 183727088Sminshall continue; 183827088Sminshall } 183927088Sminshall perror("telnet: connect"); 184027088Sminshall signal(SIGINT, SIG_DFL); 184127088Sminshall return; 184227088Sminshall } 184327088Sminshall connected++; 184427088Sminshall } while (connected == 0); 184527178Sminshall call(status, "status", "notmuch", 0); 184627088Sminshall if (setjmp(peerdied) == 0) 184727088Sminshall telnet(); 184827088Sminshall fprintf(stderr, "Connection closed by foreign host.\n"); 184927088Sminshall exit(1); 185027088Sminshall } 185127088Sminshall 185227088Sminshall 185327088Sminshall #define HELPINDENT (sizeof ("connect")) 185427088Sminshall 185527088Sminshall char openhelp[] = "connect to a site"; 185627088Sminshall char closehelp[] = "close current connection"; 185727088Sminshall char quithelp[] = "exit telnet"; 185827088Sminshall char zhelp[] = "suspend telnet"; 185927088Sminshall char escapehelp[] = "set escape character"; 186027088Sminshall char statushelp[] = "print status information"; 186127088Sminshall char helphelp[] = "print help information"; 186227110Sminshall char sendhelp[] = "transmit special characters ('send ?' for more)"; 186327178Sminshall char sethelp[] = "set operating parameters ('set ?' for more)"; 186427178Sminshall char togglestring[] ="toggle operating parameters ('toggle ?' for more)"; 186527178Sminshall char displayhelp[] = "display operating parameters"; 186627178Sminshall char modehelp[] = 186727178Sminshall "try to enter line-by-line or character-at-a-time mode"; 186827088Sminshall 186927088Sminshall int help(); 187027088Sminshall 187127088Sminshall struct cmd cmdtab[] = { 187227110Sminshall { "open", openhelp, tn, 1, 0 }, 187327110Sminshall { "close", closehelp, bye, 1, 1 }, 187427110Sminshall { "quit", quithelp, quit, 1, 0 }, 187527110Sminshall { "z", zhelp, suspend, 1, 0 }, 187627110Sminshall { "escape", escapehelp, setescape, 1, 0 }, 187727110Sminshall { "status", statushelp, status, 1, 0 }, 187827178Sminshall { "crmod", crmodhelp, togcrmod, 1, 0 }, 187927110Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 188027110Sminshall { "transmit", sendhelp, sendcmd, 0, 1 }, 188127110Sminshall { "xmit", sendhelp, sendcmd, 0, 1 }, 188227178Sminshall { "set", sethelp, setcmd, 1, 0 }, 188327110Sminshall { "toggle", togglestring, toggle, 1, 0 }, 188427178Sminshall { "display", displayhelp, display, 1, 0 }, 188527178Sminshall { "mode", modehelp, modecmd, 1, 1 }, 188627110Sminshall { "?", helphelp, help, 1, 0 }, 188727110Sminshall { "help", helphelp, help, 0, 0 }, 188827088Sminshall 0 188927088Sminshall }; 189027088Sminshall 189127088Sminshall 189227088Sminshall /* 189327088Sminshall * Help command. 189427088Sminshall */ 189527088Sminshall help(argc, argv) 189627088Sminshall int argc; 189727088Sminshall char *argv[]; 189827088Sminshall { 189927088Sminshall register struct cmd *c; 190027088Sminshall 190127088Sminshall if (argc == 1) { 190227088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 190327088Sminshall for (c = cmdtab; c->name; c++) 190427088Sminshall if (c->dohelp) { 190527088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 190627088Sminshall c->help); 190727088Sminshall } 190827088Sminshall return; 190927088Sminshall } 191027088Sminshall while (--argc > 0) { 191127088Sminshall register char *arg; 191227088Sminshall arg = *++argv; 191327088Sminshall c = getcmd(arg); 191427186Sminshall if (c == Ambiguous(struct cmd *)) 191527088Sminshall printf("?Ambiguous help command %s\n", arg); 191627088Sminshall else if (c == (struct cmd *)0) 191727088Sminshall printf("?Invalid help command %s\n", arg); 191827088Sminshall else 191927088Sminshall printf("%s\n", c->help); 192027088Sminshall } 192127088Sminshall } 192227088Sminshall /* 192327088Sminshall * Call routine with argc, argv set from args (terminated by 0). 192427088Sminshall * VARARGS2 192527088Sminshall */ 192627088Sminshall call(routine, args) 192727088Sminshall int (*routine)(); 192827186Sminshall char *args; 192927088Sminshall { 193027186Sminshall register char **argp; 193127088Sminshall register int argc; 193227088Sminshall 193327088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 193427088Sminshall ; 193527088Sminshall (*routine)(argc, &args); 193627088Sminshall } 193727088Sminshall 193827088Sminshall makeargv() 193927088Sminshall { 194027088Sminshall register char *cp; 194127088Sminshall register char **argp = margv; 194227088Sminshall 194327088Sminshall margc = 0; 194427088Sminshall for (cp = line; *cp;) { 194527088Sminshall while (isspace(*cp)) 194627088Sminshall cp++; 194727088Sminshall if (*cp == '\0') 194827088Sminshall break; 194927088Sminshall *argp++ = cp; 195027088Sminshall margc += 1; 195127088Sminshall while (*cp != '\0' && !isspace(*cp)) 195227088Sminshall cp++; 195327088Sminshall if (*cp == '\0') 195427088Sminshall break; 195527088Sminshall *cp++ = '\0'; 195627088Sminshall } 195727088Sminshall *argp++ = 0; 195827088Sminshall } 195927088Sminshall 196027088Sminshall char ** 196127088Sminshall getnextcmd(name) 196227088Sminshall char *name; 196327088Sminshall { 196427088Sminshall struct cmd *c = (struct cmd *) name; 196527088Sminshall 196627088Sminshall return (char **) (c+1); 196727088Sminshall } 196827088Sminshall 196927088Sminshall struct cmd * 197027088Sminshall getcmd(name) 197127088Sminshall char *name; 197227088Sminshall { 197327088Sminshall return (struct cmd *) genget(name, (char **) cmdtab, getnextcmd); 197427088Sminshall } 197527088Sminshall 197627088Sminshall command(top) 197727088Sminshall int top; 197827088Sminshall { 197927088Sminshall register struct cmd *c; 198027088Sminshall 198127110Sminshall setcommandmode(); 198227088Sminshall if (!top) 198327088Sminshall putchar('\n'); 198427088Sminshall else 198527088Sminshall signal(SIGINT, SIG_DFL); 198627088Sminshall for (;;) { 198727088Sminshall printf("%s> ", prompt); 198827088Sminshall if (gets(line) == 0) { 198927088Sminshall if (feof(stdin)) 199027088Sminshall quit(); 199127088Sminshall break; 199227088Sminshall } 199327088Sminshall if (line[0] == 0) 199427088Sminshall break; 199527088Sminshall makeargv(); 199627088Sminshall c = getcmd(margv[0]); 199727186Sminshall if (c == Ambiguous(struct cmd *)) { 199827088Sminshall printf("?Ambiguous command\n"); 199927088Sminshall continue; 200027088Sminshall } 200127088Sminshall if (c == 0) { 200227088Sminshall printf("?Invalid command\n"); 200327088Sminshall continue; 200427088Sminshall } 200527088Sminshall if (c->needconnect && !connected) { 200627088Sminshall printf("?Need to be connected first.\n"); 200727088Sminshall continue; 200827088Sminshall } 200927088Sminshall (*c->handler)(margc, margv); 201027088Sminshall if (c->handler != help) 201127088Sminshall break; 201227088Sminshall } 201327088Sminshall if (!top) { 201427110Sminshall if (!connected) { 201527088Sminshall longjmp(toplevel, 1); 201627110Sminshall /*NOTREACHED*/ 201727110Sminshall } 201827110Sminshall setconnmode(); 201927088Sminshall } 202027088Sminshall } 202127186Sminshall 202227186Sminshall /* 202327186Sminshall * main. Parse arguments, invoke the protocol or command parser. 202427186Sminshall */ 202527186Sminshall 202627186Sminshall 202727186Sminshall main(argc, argv) 202827186Sminshall int argc; 202927186Sminshall char *argv[]; 203027186Sminshall { 203127186Sminshall sp = getservbyname("telnet", "tcp"); 203227186Sminshall if (sp == 0) { 203327186Sminshall fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 203427186Sminshall exit(1); 203527186Sminshall } 203627186Sminshall NetTrace = stdout; 203727186Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 203827186Sminshall ioctl(0, TIOCGETC, (char *)&otc); 203927186Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 2040*27228Sminshall #if defined(LNOFLSH) 2041*27228Sminshall ioctl(0, TIOCLGET, (char *)&autoflush); 2042*27228Sminshall autoflush &= LNOFLSH; 2043*27228Sminshall #endif /* LNOFLSH */ 204427186Sminshall ntc = otc; 204527186Sminshall ntc.t_eofc = -1; /* we don't want to use EOF */ 2046*27228Sminshall nltc = oltc; 204727186Sminshall nttyb = ottyb; 204827186Sminshall setbuf(stdin, (char *)0); 204927186Sminshall setbuf(stdout, (char *)0); 205027186Sminshall prompt = argv[0]; 205127186Sminshall if (argc > 1 && !strcmp(argv[1], "-d")) { 205227186Sminshall debug = 1; 205327186Sminshall argv++; 205427186Sminshall argc--; 205527186Sminshall } 205627186Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 205727186Sminshall argv++; 205827186Sminshall argc--; 205927186Sminshall if (argc > 1) { /* get file name */ 206027186Sminshall NetTrace = fopen(argv[1], "w"); 206127186Sminshall argv++; 206227186Sminshall argc--; 206327186Sminshall if (NetTrace == NULL) { 206427186Sminshall NetTrace = stdout; 206527186Sminshall } 206627186Sminshall } 206727186Sminshall } 206827186Sminshall if (argc != 1) { 206927186Sminshall if (setjmp(toplevel) != 0) 207027186Sminshall exit(0); 207127186Sminshall tn(argc, argv); 207227186Sminshall } 207327186Sminshall setjmp(toplevel); 207427186Sminshall for (;;) 207527186Sminshall command(1); 207627186Sminshall } 2077