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*27088Sminshall static char sccsid[] = "@(#)telnet.c 5.7 (Berkeley) 04/15/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> 239217Ssam 249217Ssam #include <netinet/in.h> 259217Ssam 2612212Ssam #define TELOPTS 2712212Ssam #include <arpa/telnet.h> 2812212Ssam 296000Sroot #include <stdio.h> 306000Sroot #include <ctype.h> 316000Sroot #include <errno.h> 326000Sroot #include <signal.h> 336000Sroot #include <setjmp.h> 348345Ssam #include <netdb.h> 359217Ssam 366000Sroot #define strip(x) ((x)&0177) 376000Sroot 386000Sroot char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; 39*27088Sminshall #define TTYADD(c) { if (!flushing) { *tfrontp++ = c; } } 40*27088Sminshall 418378Ssam char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 42*27088Sminshall #define NETADD(c) { *nfrontp++ = c; } 43*27088Sminshall #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } 44*27088Sminshall #define NETLOC() (nfrontp) 45*27088Sminshall char *neturg = 0; /* one past last byte of urgent data */ 466000Sroot 476000Sroot char hisopts[256]; 486000Sroot char myopts[256]; 496000Sroot 506000Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 516000Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 526000Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 536000Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 546000Sroot 55*27088Sminshall struct cmd { 56*27088Sminshall char *name; /* command name */ 57*27088Sminshall char *help; /* help string */ 58*27088Sminshall int (*handler)(); /* routine which executes command */ 59*27088Sminshall int dohelp; /* Should we give general help information? */ 60*27088Sminshall int needconnect; /* Do we need to be connected to execute? */ 61*27088Sminshall }; 62*27088Sminshall 636000Sroot int connected; 646000Sroot int net; 65*27088Sminshall int tout; 669972Ssam int showoptions = 0; 677377Sfeldman int options; 6810339Ssam int debug = 0; 699972Ssam int crmod = 0; 70*27088Sminshall int netdata = 0; 7127021Sminshall static FILE *NetTrace; 7225289Skarels int telnetport = 1; 73*27088Sminshall 74*27088Sminshall int flushing = 0; /* are we in TELNET SYNCH mode? */ 75*27088Sminshall 766000Sroot char *prompt; 779972Ssam char escape = CTRL(]); 786000Sroot 796000Sroot char line[200]; 806000Sroot int margc; 816000Sroot char *margv[20]; 826000Sroot 836000Sroot jmp_buf toplevel; 846000Sroot jmp_buf peerdied; 856000Sroot 866000Sroot extern int errno; 876000Sroot 886000Sroot 899972Ssam struct sockaddr_in sin; 906000Sroot 916000Sroot int intr(), deadpeer(); 926000Sroot char *control(); 936000Sroot struct cmd *getcmd(); 948345Ssam struct servent *sp; 956000Sroot 9613076Ssam struct tchars otc; 9713076Ssam struct ltchars oltc; 9813076Ssam struct sgttyb ottyb; 998378Ssam 1006000Sroot main(argc, argv) 1016000Sroot int argc; 1026000Sroot char *argv[]; 1036000Sroot { 1048345Ssam sp = getservbyname("telnet", "tcp"); 1058345Ssam if (sp == 0) { 1068345Ssam fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 1078345Ssam exit(1); 1088345Ssam } 10927021Sminshall NetTrace = stdout; 11013076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 11113076Ssam ioctl(0, TIOCGETC, (char *)&otc); 11213076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 1136000Sroot setbuf(stdin, 0); 1146000Sroot setbuf(stdout, 0); 1156000Sroot prompt = argv[0]; 11617484Sleres if (argc > 1 && !strcmp(argv[1], "-d")) { 11717484Sleres debug = 1; 11817484Sleres argv++; 11917484Sleres argc--; 12017484Sleres } 12127021Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 12227021Sminshall argv++; 12327021Sminshall argc--; 12427021Sminshall if (argc > 1) { /* get file name */ 12527021Sminshall NetTrace = fopen(argv[1], "w"); 12627021Sminshall argv++; 12727021Sminshall argc--; 12827021Sminshall if (NetTrace == NULL) { 12927021Sminshall NetTrace = stdout; 13027021Sminshall } 13127021Sminshall } 13227021Sminshall } 1336000Sroot if (argc != 1) { 1346000Sroot if (setjmp(toplevel) != 0) 1356000Sroot exit(0); 1366000Sroot tn(argc, argv); 1376000Sroot } 1386000Sroot setjmp(toplevel); 1396000Sroot for (;;) 1406000Sroot command(1); 1416000Sroot } 1426000Sroot 1438377Ssam char *hostname; 1448377Ssam char hnamebuf[32]; 1456000Sroot 146*27088Sminshall 147*27088Sminshall char ** 148*27088Sminshall genget(name, table, next) 149*27088Sminshall char *name; /* name to match */ 150*27088Sminshall char **table; /* name entry in table */ 151*27088Sminshall char **(*next)(); /* routine to return next entry in table */ 1526000Sroot { 153*27088Sminshall register char *p, *q; 154*27088Sminshall register char **c, **found; 155*27088Sminshall register int nmatches, longest; 1566000Sroot 157*27088Sminshall longest = 0; 158*27088Sminshall nmatches = 0; 159*27088Sminshall found = 0; 160*27088Sminshall for (c = table; p = *c; c = (*next)(c)) { 161*27088Sminshall for (q = name; *q == *p++; q++) 162*27088Sminshall if (*q == 0) /* exact match? */ 163*27088Sminshall return (c); 164*27088Sminshall if (!*q) { /* the name was a prefix */ 165*27088Sminshall if (q - name > longest) { 166*27088Sminshall longest = q - name; 167*27088Sminshall nmatches = 1; 168*27088Sminshall found = c; 169*27088Sminshall } else if (q - name == longest) 170*27088Sminshall nmatches++; 1718377Ssam } 1726000Sroot } 173*27088Sminshall if (nmatches > 1) 174*27088Sminshall return ((char **)-1); 175*27088Sminshall return (found); 1766000Sroot } 1776000Sroot 1786000Sroot 17913076Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 18013076Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 1819972Ssam 1826000Sroot mode(f) 1836000Sroot register int f; 1846000Sroot { 1858378Ssam static int prevmode = 0; 18613076Ssam struct tchars *tc; 18713076Ssam struct ltchars *ltc; 18813076Ssam struct sgttyb sb; 18913076Ssam int onoff, old; 1906000Sroot 1918378Ssam if (prevmode == f) 1928378Ssam return (f); 1938378Ssam old = prevmode; 1948378Ssam prevmode = f; 19513076Ssam sb = ottyb; 1966000Sroot switch (f) { 1978378Ssam 1986000Sroot case 0: 1996000Sroot onoff = 0; 2009972Ssam tc = &otc; 20113076Ssam ltc = &oltc; 2026000Sroot break; 2036000Sroot 2046000Sroot case 1: 2056000Sroot case 2: 20613076Ssam sb.sg_flags |= CBREAK; 2078378Ssam if (f == 1) 20813076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 2098378Ssam else 21013076Ssam sb.sg_flags |= ECHO|CRMOD; 21113076Ssam sb.sg_erase = sb.sg_kill = -1; 2129972Ssam tc = ¬c; 21313076Ssam ltc = &noltc; 2146000Sroot onoff = 1; 2159972Ssam break; 2169972Ssam 2179972Ssam default: 2189972Ssam return; 2196000Sroot } 22013076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 22113076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 22213076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 2236000Sroot ioctl(fileno(stdin), FIONBIO, &onoff); 2246000Sroot ioctl(fileno(stdout), FIONBIO, &onoff); 2256000Sroot return (old); 2266000Sroot } 2276000Sroot 2286000Sroot char sibuf[BUFSIZ], *sbp; 2296000Sroot char tibuf[BUFSIZ], *tbp; 2306000Sroot int scc, tcc; 2316000Sroot 2326000Sroot /* 2336000Sroot * Select from tty and network... 2346000Sroot */ 235*27088Sminshall telnet() 2366000Sroot { 2376000Sroot register int c; 238*27088Sminshall int tin = fileno(stdin); 2396000Sroot int on = 1; 2406000Sroot 241*27088Sminshall tout = fileno(stdout); 2428378Ssam (void) mode(2); 243*27088Sminshall ioctl(net, FIONBIO, &on); 244*27088Sminshall if (telnetport && !hisopts[TELOPT_SGA]) { 24517922Sralph willoption(TELOPT_SGA); 246*27088Sminshall } 2476000Sroot for (;;) { 248*27088Sminshall long ibits = 0, obits = 0, xbits = 0; 2496000Sroot 2506000Sroot if (nfrontp - nbackp) 251*27088Sminshall obits |= (1 << net); 2526000Sroot else 2536000Sroot ibits |= (1 << tin); 2546000Sroot if (tfrontp - tbackp) 2556000Sroot obits |= (1 << tout); 2566000Sroot else 257*27088Sminshall ibits |= (1 << net); 2586000Sroot if (scc < 0 && tcc < 0) 2596000Sroot break; 260*27088Sminshall if (flushing) { 261*27088Sminshall xbits = 0; 262*27088Sminshall } else { 263*27088Sminshall xbits = (1 << net); 264*27088Sminshall } 265*27088Sminshall select(16, &ibits, &obits, &xbits, 0); 266*27088Sminshall if (ibits == 0 && obits == 0 && xbits == 0) { 2676000Sroot sleep(5); 2686000Sroot continue; 2696000Sroot } 2706000Sroot 2716000Sroot /* 272*27088Sminshall * Any urgent data? 273*27088Sminshall */ 274*27088Sminshall if (xbits) { 275*27088Sminshall flushing = 1; 276*27088Sminshall ttyflush(); /* flush already enqueued data */ 277*27088Sminshall } 278*27088Sminshall 279*27088Sminshall /* 2806000Sroot * Something to read from the network... 2816000Sroot */ 282*27088Sminshall if (ibits & (1 << net)) { 283*27088Sminshall scc = read(net, sibuf, sizeof (sibuf)); 2846000Sroot if (scc < 0 && errno == EWOULDBLOCK) 2856000Sroot scc = 0; 2866000Sroot else { 2876000Sroot if (scc <= 0) 2886000Sroot break; 2896000Sroot sbp = sibuf; 290*27088Sminshall if (netdata) { 29127021Sminshall Dump('<', sbp, scc); 29227021Sminshall } 2936000Sroot } 2946000Sroot } 2956000Sroot 2966000Sroot /* 2976000Sroot * Something to read from the tty... 2986000Sroot */ 2996000Sroot if (ibits & (1 << tin)) { 3008378Ssam tcc = read(tin, tibuf, sizeof (tibuf)); 3016000Sroot if (tcc < 0 && errno == EWOULDBLOCK) 3026000Sroot tcc = 0; 3036000Sroot else { 3046000Sroot if (tcc <= 0) 3056000Sroot break; 3066000Sroot tbp = tibuf; 3076000Sroot } 3086000Sroot } 3096000Sroot 3106000Sroot while (tcc > 0) { 3116000Sroot register int c; 3126000Sroot 3136000Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 3146000Sroot break; 3156000Sroot c = *tbp++ & 0377, tcc--; 3166000Sroot if (strip(c) == escape) { 3176000Sroot command(0); 3186000Sroot tcc = 0; 3196000Sroot break; 3206000Sroot } 32117922Sralph switch (c) { 32227021Sminshall case '\n'|0x80: 32317922Sralph case '\n': 32427021Sminshall /* 32527021Sminshall * If echoing is happening locally, 32627021Sminshall * then a newline (unix) is CRLF (TELNET). 32727021Sminshall */ 328*27088Sminshall if (!hisopts[TELOPT_ECHO]) { 329*27088Sminshall NETADD('\r'); 330*27088Sminshall } 331*27088Sminshall NETADD('\n'); 33217922Sralph break; 33327021Sminshall case '\r'|0x80: 33417922Sralph case '\r': 335*27088Sminshall NET2ADD('\r', '\0'); 33617922Sralph break; 33717922Sralph case IAC: 338*27088Sminshall NET2ADD(IAC, IAC); 33927021Sminshall break; 34017922Sralph default: 341*27088Sminshall NETADD(c); 34217922Sralph break; 34317922Sralph } 3446000Sroot } 345*27088Sminshall if ((obits & (1 << net)) && (nfrontp - nbackp) > 0) 346*27088Sminshall netflush(net); 3476000Sroot if (scc > 0) 3486000Sroot telrcv(); 3496000Sroot if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0) 350*27088Sminshall ttyflush(); 3516000Sroot } 3528378Ssam (void) mode(0); 3536000Sroot } 3546000Sroot 3556000Sroot /* 3566000Sroot * Telnet receiver states for fsm 3576000Sroot */ 3586000Sroot #define TS_DATA 0 3596000Sroot #define TS_IAC 1 3606000Sroot #define TS_WILL 2 3616000Sroot #define TS_WONT 3 3626000Sroot #define TS_DO 4 3636000Sroot #define TS_DONT 5 36427021Sminshall #define TS_CR 6 3656000Sroot 3666000Sroot telrcv() 3676000Sroot { 3686000Sroot register int c; 3696000Sroot static int state = TS_DATA; 3706000Sroot 3716000Sroot while (scc > 0) { 3726000Sroot c = *sbp++ & 0377, scc--; 3736000Sroot switch (state) { 3746000Sroot 37527021Sminshall case TS_CR: 37627021Sminshall state = TS_DATA; 37727021Sminshall if ((c == '\0') || (c == '\n')) { 37827021Sminshall break; /* by now, we ignore \n */ 37927021Sminshall } 38027021Sminshall 3816000Sroot case TS_DATA: 3829972Ssam if (c == IAC) { 3836000Sroot state = TS_IAC; 3849972Ssam continue; 3859972Ssam } 38627021Sminshall if (c == '\r') { 38727021Sminshall if (scc > 0) { 38827021Sminshall c = *sbp&0377; 38927021Sminshall if (c == 0) { 39027021Sminshall sbp++, scc--; 391*27088Sminshall TTYADD('\r'); 39227021Sminshall /* 39327021Sminshall * The following hack is needed since we can't 39427021Sminshall * set CRMOD on output only. Machines like 39527021Sminshall * MULTICS like to send \r without \n; since 39627021Sminshall * we must turn off CRMOD to get proper input, 39727021Sminshall * the mapping is done here (sigh). 39827021Sminshall */ 39927021Sminshall if (crmod) { 400*27088Sminshall TTYADD('\n'); 40127021Sminshall } 40227021Sminshall } else if (!hisopts[TELOPT_ECHO] && 40327021Sminshall (c == '\n')) { 40427021Sminshall sbp++, scc--; 405*27088Sminshall TTYADD('\n'); 40627021Sminshall } else { 407*27088Sminshall TTYADD('\r'); 40827021Sminshall } 40927021Sminshall } else { 41027021Sminshall state = TS_CR; 411*27088Sminshall TTYADD('\r'); 41227021Sminshall } 41327021Sminshall } else { 414*27088Sminshall TTYADD(c); 41527021Sminshall } 4166000Sroot continue; 4176000Sroot 4186000Sroot case TS_IAC: 4196000Sroot switch (c) { 4206000Sroot 4216000Sroot case WILL: 4226000Sroot state = TS_WILL; 4236000Sroot continue; 4246000Sroot 4256000Sroot case WONT: 4266000Sroot state = TS_WONT; 4276000Sroot continue; 4286000Sroot 4296000Sroot case DO: 4306000Sroot state = TS_DO; 4316000Sroot continue; 4326000Sroot 4336000Sroot case DONT: 4346000Sroot state = TS_DONT; 4356000Sroot continue; 4366000Sroot 4376000Sroot case DM: 438*27088Sminshall /* 439*27088Sminshall * We may have missed an urgent notification, 440*27088Sminshall * so make sure we flush whatever is in the 441*27088Sminshall * buffer currently. 442*27088Sminshall */ 443*27088Sminshall flushing = 1; 444*27088Sminshall ttyflush(); 445*27088Sminshall flushing = stilloob(net); 4466000Sroot break; 4476000Sroot 4486000Sroot case NOP: 4496000Sroot case GA: 4506000Sroot break; 4516000Sroot 4526000Sroot default: 4536000Sroot break; 4546000Sroot } 4556000Sroot state = TS_DATA; 4566000Sroot continue; 4576000Sroot 4586000Sroot case TS_WILL: 4598345Ssam printoption("RCVD", will, c, !hisopts[c]); 4606000Sroot if (!hisopts[c]) 4616000Sroot willoption(c); 4626000Sroot state = TS_DATA; 4636000Sroot continue; 4646000Sroot 4656000Sroot case TS_WONT: 4668345Ssam printoption("RCVD", wont, c, hisopts[c]); 4676000Sroot if (hisopts[c]) 4686000Sroot wontoption(c); 4696000Sroot state = TS_DATA; 4706000Sroot continue; 4716000Sroot 4726000Sroot case TS_DO: 4738345Ssam printoption("RCVD", doopt, c, !myopts[c]); 4746000Sroot if (!myopts[c]) 4756000Sroot dooption(c); 4766000Sroot state = TS_DATA; 4776000Sroot continue; 4786000Sroot 4796000Sroot case TS_DONT: 4808345Ssam printoption("RCVD", dont, c, myopts[c]); 4816000Sroot if (myopts[c]) { 4826000Sroot myopts[c] = 0; 4836000Sroot sprintf(nfrontp, wont, c); 4848378Ssam nfrontp += sizeof (wont) - 2; 4858345Ssam printoption("SENT", wont, c); 4866000Sroot } 4876000Sroot state = TS_DATA; 4886000Sroot continue; 4896000Sroot } 4906000Sroot } 4916000Sroot } 4926000Sroot 4936000Sroot willoption(option) 4946000Sroot int option; 4956000Sroot { 4966000Sroot char *fmt; 4976000Sroot 4986000Sroot switch (option) { 4996000Sroot 5006000Sroot case TELOPT_ECHO: 5018378Ssam (void) mode(1); 5026000Sroot 5036000Sroot case TELOPT_SGA: 5046000Sroot hisopts[option] = 1; 5056000Sroot fmt = doopt; 5066000Sroot break; 5076000Sroot 5086000Sroot case TELOPT_TM: 5096000Sroot fmt = dont; 5106000Sroot break; 5116000Sroot 5126000Sroot default: 5136000Sroot fmt = dont; 5146000Sroot break; 5156000Sroot } 5166024Ssam sprintf(nfrontp, fmt, option); 5178378Ssam nfrontp += sizeof (dont) - 2; 5188345Ssam printoption("SENT", fmt, option); 5196000Sroot } 5206000Sroot 5216000Sroot wontoption(option) 5226000Sroot int option; 5236000Sroot { 5246000Sroot char *fmt; 5256000Sroot 5266000Sroot switch (option) { 5276000Sroot 5286000Sroot case TELOPT_ECHO: 5298378Ssam (void) mode(2); 5306000Sroot 5316000Sroot case TELOPT_SGA: 5326000Sroot hisopts[option] = 0; 5336000Sroot fmt = dont; 5346000Sroot break; 5356000Sroot 5366000Sroot default: 5376000Sroot fmt = dont; 5386000Sroot } 5396000Sroot sprintf(nfrontp, fmt, option); 5408378Ssam nfrontp += sizeof (doopt) - 2; 5418345Ssam printoption("SENT", fmt, option); 5426000Sroot } 5436000Sroot 5446000Sroot dooption(option) 5456000Sroot int option; 5466000Sroot { 5476000Sroot char *fmt; 5486000Sroot 5496000Sroot switch (option) { 5506000Sroot 5516000Sroot case TELOPT_TM: 5526000Sroot fmt = wont; 5536000Sroot break; 5546000Sroot 55513231Ssam case TELOPT_ECHO: 55613231Ssam (void) mode(2); 55713231Ssam fmt = will; 55813231Ssam hisopts[option] = 0; 55913231Ssam break; 56013231Ssam 5616000Sroot case TELOPT_SGA: 5626000Sroot fmt = will; 5636000Sroot break; 5646000Sroot 5656000Sroot default: 5666000Sroot fmt = wont; 5676000Sroot break; 5686000Sroot } 5696000Sroot sprintf(nfrontp, fmt, option); 5708378Ssam nfrontp += sizeof (doopt) - 2; 5718345Ssam printoption("SENT", fmt, option); 5726000Sroot } 5736000Sroot 5746000Sroot /* 575*27088Sminshall * Check to see if any out-of-band data exists on a socket (for 576*27088Sminshall * Telnet "synch" processing). 5776000Sroot */ 5786000Sroot 579*27088Sminshall int 580*27088Sminshall stilloob(s) 581*27088Sminshall int s; /* socket number */ 5826024Ssam { 583*27088Sminshall struct timeval *timeout = { 0 }; 584*27088Sminshall long excepts = (1<<s); 5859972Ssam 586*27088Sminshall if (select(s+1, 0, 0, &excepts, timeout) < 0) { 587*27088Sminshall perror("select"); 588*27088Sminshall quit(); 589*27088Sminshall } 590*27088Sminshall if (excepts) { 591*27088Sminshall return 1; 592*27088Sminshall } else { 593*27088Sminshall return 0; 594*27088Sminshall } 5956024Ssam } 5966024Ssam 5976000Sroot /* 5986000Sroot * Construct a control character sequence 5996000Sroot * for a special character. 6006000Sroot */ 6016000Sroot char * 6026000Sroot control(c) 6036000Sroot register int c; 6046000Sroot { 6056000Sroot static char buf[3]; 6066000Sroot 6076000Sroot if (c == 0177) 6086000Sroot return ("^?"); 6096000Sroot if (c >= 040) { 6106000Sroot buf[0] = c; 6116000Sroot buf[1] = 0; 6126000Sroot } else { 6136000Sroot buf[0] = '^'; 6146000Sroot buf[1] = '@'+c; 6156000Sroot buf[2] = 0; 6166000Sroot } 6176000Sroot return (buf); 6186000Sroot } 6196000Sroot 6206000Sroot deadpeer() 6216000Sroot { 6228378Ssam (void) mode(0); 6236000Sroot longjmp(peerdied, -1); 6246000Sroot } 6256000Sroot 6266000Sroot intr() 6276000Sroot { 6288378Ssam (void) mode(0); 6296000Sroot longjmp(toplevel, -1); 6306000Sroot } 6316000Sroot 632*27088Sminshall ttyflush() 6336000Sroot { 634*27088Sminshall int n; 6356000Sroot 636*27088Sminshall if ((n = tfrontp - tbackp) > 0) { 637*27088Sminshall if (!flushing) { 638*27088Sminshall n = write(tout, tbackp, n); 639*27088Sminshall } else { 640*27088Sminshall ioctl(fileno(stdout), TIOCFLUSH, 0); 641*27088Sminshall } 642*27088Sminshall } 643*27088Sminshall if (n < 0) { 644*27088Sminshall return; 645*27088Sminshall } 646*27088Sminshall tbackp += n; 647*27088Sminshall if (tbackp == tfrontp) { 648*27088Sminshall tbackp = tfrontp = ttyobuf; 649*27088Sminshall } 6506000Sroot } 6516000Sroot 6526000Sroot netflush(fd) 6536000Sroot { 654*27088Sminshall int n; 6556000Sroot 656*27088Sminshall if ((n = nfrontp - nbackp) > 0) { 657*27088Sminshall if (!neturg) { 658*27088Sminshall n = write(fd, nbackp, n); /* normal write */ 659*27088Sminshall } else { 660*27088Sminshall n = neturg - nbackp; 661*27088Sminshall n = send(fd, nbackp, n, MSG_OOB); /* URGENT data (SYNCH) */ 6626501Ssam } 663*27088Sminshall } 664*27088Sminshall if (n < 0) { 665*27088Sminshall if (errno != ENOBUFS && errno != EWOULDBLOCK) { 666*27088Sminshall (void) mode(0); 667*27088Sminshall perror(hostname); 668*27088Sminshall close(fd); 669*27088Sminshall neturg = 0; 670*27088Sminshall longjmp(peerdied, -1); 671*27088Sminshall /*NOTREACHED*/ 67227021Sminshall } 673*27088Sminshall n = 0; 674*27088Sminshall } 675*27088Sminshall if (netdata && n) { 676*27088Sminshall Dump('>', nbackp, n); 677*27088Sminshall } 678*27088Sminshall nbackp += n; 679*27088Sminshall if (nbackp >= neturg) { 680*27088Sminshall neturg = 0; 681*27088Sminshall } 682*27088Sminshall if (nbackp == nfrontp) { 683*27088Sminshall nbackp = nfrontp = netobuf; 684*27088Sminshall } 6856000Sroot } 6866024Ssam 68727021Sminshall static 68827021Sminshall Dump(direction, buffer, length) 68927021Sminshall char direction; 69027021Sminshall char *buffer; 69127021Sminshall int length; 69227021Sminshall { 69327021Sminshall # define BYTES_PER_LINE 32 69427021Sminshall # define min(x,y) ((x<y)? x:y) 69527021Sminshall char *pThis; 69627021Sminshall int offset; 69727021Sminshall 69827021Sminshall offset = 0; 69927021Sminshall 70027021Sminshall while (length) { 70127021Sminshall /* print one line */ 70227021Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 70327021Sminshall pThis = buffer; 70427021Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 70527021Sminshall while (pThis < buffer) { 70627021Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 70727021Sminshall pThis++; 70827021Sminshall } 70927021Sminshall fprintf(NetTrace, "\n"); 71027021Sminshall length -= BYTES_PER_LINE; 71127021Sminshall offset += BYTES_PER_LINE; 71227021Sminshall if (length < 0) { 71327021Sminshall return; 71427021Sminshall } 71527021Sminshall /* find next unique line */ 71627021Sminshall } 71727021Sminshall } 71827021Sminshall 71927021Sminshall 7206293Sroot /*VARARGS*/ 7216293Sroot printoption(direction, fmt, option, what) 7226024Ssam char *direction, *fmt; 7236293Sroot int option, what; 7246024Ssam { 7258345Ssam if (!showoptions) 7268345Ssam return; 7276024Ssam printf("%s ", direction); 7286024Ssam if (fmt == doopt) 7296024Ssam fmt = "do"; 7306024Ssam else if (fmt == dont) 7316024Ssam fmt = "dont"; 7326024Ssam else if (fmt == will) 7336024Ssam fmt = "will"; 7346024Ssam else if (fmt == wont) 7356024Ssam fmt = "wont"; 7366024Ssam else 7376024Ssam fmt = "???"; 7386024Ssam if (option < TELOPT_SUPDUP) 7396293Sroot printf("%s %s", fmt, telopts[option]); 7406024Ssam else 7416293Sroot printf("%s %d", fmt, option); 7426293Sroot if (*direction == '<') { 7436293Sroot printf("\r\n"); 7446293Sroot return; 7456293Sroot } 7466293Sroot printf(" (%s)\r\n", what ? "reply" : "don't reply"); 7476024Ssam } 748*27088Sminshall 749*27088Sminshall /* 750*27088Sminshall * The following are data structures and routines for 751*27088Sminshall * the "send" command. 752*27088Sminshall * 753*27088Sminshall */ 754*27088Sminshall 755*27088Sminshall struct sendlist { 756*27088Sminshall char *name; /* How user refers to it (case independent) */ 757*27088Sminshall int what; /* Character to be sent (<0 ==> special) */ 758*27088Sminshall char *help; /* Help information (0 ==> no help) */ 759*27088Sminshall int (*routine)(); /* Routine to perform (for special ops) */ 760*27088Sminshall }; 761*27088Sminshall 762*27088Sminshall dosynch(s) 763*27088Sminshall struct sendlist *s; 764*27088Sminshall { 765*27088Sminshall /* XXX We really should purge the buffer to the network */ 766*27088Sminshall NET2ADD(IAC, DM); 767*27088Sminshall neturg = NETLOC(); 768*27088Sminshall } 769*27088Sminshall 770*27088Sminshall sendesc() 771*27088Sminshall { 772*27088Sminshall NETADD(escape); 773*27088Sminshall } 774*27088Sminshall 775*27088Sminshall ayt() 776*27088Sminshall { 777*27088Sminshall NET2ADD(IAC, AYT); 778*27088Sminshall } 779*27088Sminshall 780*27088Sminshall intp() 781*27088Sminshall { 782*27088Sminshall NET2ADD(IAC, IP); 783*27088Sminshall } 784*27088Sminshall 785*27088Sminshall 786*27088Sminshall #define SENDQUESTION -1 787*27088Sminshall #define SEND2QUESTION -2 788*27088Sminshall #define SENDESCAPE -3 789*27088Sminshall 790*27088Sminshall struct sendlist Sendlist[] = { 791*27088Sminshall { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch }, 792*27088Sminshall { "brk", BREAK, "Send Telnet Break" }, 793*27088Sminshall { "break", BREAK, 0 }, 794*27088Sminshall { "ip", IP, "Send Telnet Interrupt Process" }, 795*27088Sminshall { "intp", IP, 0 }, 796*27088Sminshall { "interrupt", IP, 0 }, 797*27088Sminshall { "intr", IP, 0 }, 798*27088Sminshall { "ao", AO, "Send Telnet Abort output" }, 799*27088Sminshall { "abort", AO, 0 }, 800*27088Sminshall { "ayt", AYT, "Send Telnet 'Are You There'" }, 801*27088Sminshall { "are", AYT, 0 }, 802*27088Sminshall { "hello", AYT, 0 }, 803*27088Sminshall { "ec", EC, "Send Telnet Erase Character" }, 804*27088Sminshall { "el", EL, "Send Telnet Erase Line" }, 805*27088Sminshall { "ga", GA, "Send Telnet 'Go Ahead' sequence" }, 806*27088Sminshall { "go", GA, 0 }, 807*27088Sminshall { "nop", NOP, "Send Telnet 'No operation'" }, 808*27088Sminshall { "escape", SENDESCAPE, "Send current escape character" }, 809*27088Sminshall { "?", SENDQUESTION, "Display send options" }, 810*27088Sminshall { "help", SENDQUESTION, 0 }, 811*27088Sminshall { "??", SEND2QUESTION, "Display all send options (including aliases)" }, 812*27088Sminshall { 0 } 813*27088Sminshall }; 814*27088Sminshall 815*27088Sminshall char ** 816*27088Sminshall getnextsend(name) 817*27088Sminshall char *name; 818*27088Sminshall { 819*27088Sminshall struct sendlist *c = (struct sendlist *) name; 820*27088Sminshall 821*27088Sminshall return (char **) (c+1); 822*27088Sminshall } 823*27088Sminshall 824*27088Sminshall struct sendlist * 825*27088Sminshall getsend(name) 826*27088Sminshall char *name; 827*27088Sminshall { 828*27088Sminshall return (struct sendlist *) genget(name, (char **) Sendlist, getnextsend); 829*27088Sminshall } 830*27088Sminshall 831*27088Sminshall sendcmd(argc, argv) 832*27088Sminshall int argc; 833*27088Sminshall char **argv; 834*27088Sminshall { 835*27088Sminshall int what; /* what we are sending this time */ 836*27088Sminshall int count; /* how many bytes we are going to need to send */ 837*27088Sminshall int hadsynch; /* are we going to process a "synch"? */ 838*27088Sminshall int i; 839*27088Sminshall struct sendlist *s; /* pointer to current command */ 840*27088Sminshall 841*27088Sminshall if (argc < 2) { 842*27088Sminshall printf("need at least one argument for 'send' command\n"); 843*27088Sminshall printf("'send ?' for help\n"); 844*27088Sminshall return; 845*27088Sminshall } 846*27088Sminshall /* 847*27088Sminshall * First, validate all the send arguments. 848*27088Sminshall * In addition, we see how much space we are going to need, and 849*27088Sminshall * whether or not we will be doing a "SYNCH" operation (which 850*27088Sminshall * flushes the network queue). 851*27088Sminshall */ 852*27088Sminshall count = 0; 853*27088Sminshall hadsynch = 0; 854*27088Sminshall for (i = 1; i < argc; i++) { 855*27088Sminshall s = getsend(argv[i]); 856*27088Sminshall if (s == 0) { 857*27088Sminshall printf("Unknown send argument '%s'\n'send ?' for help.\n", 858*27088Sminshall argv[i]); 859*27088Sminshall return; 860*27088Sminshall } else if (s == (struct sendlist *) -1) { 861*27088Sminshall printf("Ambiguous send argument '%s'\n'send ?' for help.\n", 862*27088Sminshall argv[i]); 863*27088Sminshall return; 864*27088Sminshall } 865*27088Sminshall switch (s->what) { 866*27088Sminshall case SENDQUESTION: 867*27088Sminshall case SEND2QUESTION: 868*27088Sminshall break; 869*27088Sminshall case SENDESCAPE: 870*27088Sminshall count += 1; 871*27088Sminshall break; 872*27088Sminshall case SYNCH: 873*27088Sminshall hadsynch = 1; 874*27088Sminshall count += 2; 875*27088Sminshall break; 876*27088Sminshall default: 877*27088Sminshall count += 2; 878*27088Sminshall break; 879*27088Sminshall } 880*27088Sminshall } 881*27088Sminshall /* Now, do we have enough room? */ 882*27088Sminshall if (netobuf+sizeof netobuf-nfrontp-1 < count) { 883*27088Sminshall printf("There is not enough room in the buffer TO the network\n"); 884*27088Sminshall printf("to process your request. Nothing will be done.\n"); 885*27088Sminshall printf("('send synch' will throw away most data in the network\n"); 886*27088Sminshall printf("buffer, if this might help.)\n"); 887*27088Sminshall return; 888*27088Sminshall } 889*27088Sminshall /* OK, they are all OK, now go through again and actually send */ 890*27088Sminshall for (i = 1; i < argc; i++) { 891*27088Sminshall if (!(s = getsend(argv[i]))) { 892*27088Sminshall fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 893*27088Sminshall quit(); 894*27088Sminshall /*NOTREACHED*/ 895*27088Sminshall } 896*27088Sminshall if (s->routine) { 897*27088Sminshall (*s->routine)(s); 898*27088Sminshall } else { 899*27088Sminshall switch (what = s->what) { 900*27088Sminshall case SENDQUESTION: 901*27088Sminshall case SEND2QUESTION: 902*27088Sminshall for (s = Sendlist; s->name; s++) { 903*27088Sminshall if (s->help || (what == SEND2QUESTION)) { 904*27088Sminshall printf(s->name); 905*27088Sminshall if (s->help) { 906*27088Sminshall printf("\t%s", s->help); 907*27088Sminshall } 908*27088Sminshall printf("\n"); 909*27088Sminshall } 910*27088Sminshall } 911*27088Sminshall break; 912*27088Sminshall case SENDESCAPE: 913*27088Sminshall NETADD(escape); 914*27088Sminshall break; 915*27088Sminshall default: 916*27088Sminshall NET2ADD(IAC, what); 917*27088Sminshall break; 918*27088Sminshall } 919*27088Sminshall } 920*27088Sminshall } 921*27088Sminshall } 922*27088Sminshall 923*27088Sminshall /* 924*27088Sminshall * The following are the routines and data structures referred 925*27088Sminshall * to by the arguments to the "toggle" command. 926*27088Sminshall */ 927*27088Sminshall 928*27088Sminshall setdebug() 929*27088Sminshall { 930*27088Sminshall 931*27088Sminshall debug = debug ? 0 : 1; 932*27088Sminshall printf("%s turn on socket level debugging.\n", 933*27088Sminshall debug ? "Will" : "Won't"); 934*27088Sminshall fflush(stdout); 935*27088Sminshall if (net > 0 && 936*27088Sminshall setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 937*27088Sminshall perror("setsockopt (SO_DEBUG)"); 938*27088Sminshall } 939*27088Sminshall 940*27088Sminshall static 941*27088Sminshall setnetdata() 942*27088Sminshall { 943*27088Sminshall 944*27088Sminshall netdata = !netdata; 945*27088Sminshall printf("%s turn on printing of raw network traffic.\n", 946*27088Sminshall netdata ? "Will" : "Wont"); 947*27088Sminshall } 948*27088Sminshall 949*27088Sminshall setoptions() 950*27088Sminshall { 951*27088Sminshall 952*27088Sminshall showoptions = !showoptions; 953*27088Sminshall printf("%s show option processing.\n", showoptions ? "Will" : "Won't"); 954*27088Sminshall fflush(stdout); 955*27088Sminshall } 956*27088Sminshall 957*27088Sminshall int togglehelp(); 958*27088Sminshall 959*27088Sminshall struct cmd togglelist[] = { 960*27088Sminshall { "debug", "toggle debugging", setdebug, 1 }, 961*27088Sminshall { "options", "toggle viewing of options processing", setoptions, 1 }, 962*27088Sminshall { "netdata", "toggle printing of hexadecimal network data", 963*27088Sminshall setnetdata, 1 }, 964*27088Sminshall { "?", "display help information", togglehelp, 1 }, 965*27088Sminshall { "help", "display help information", togglehelp, 0 }, 966*27088Sminshall { 0 } 967*27088Sminshall }; 968*27088Sminshall 969*27088Sminshall togglehelp() 970*27088Sminshall { 971*27088Sminshall struct cmd *c; 972*27088Sminshall 973*27088Sminshall for (c = togglelist; c->name; c++) { 974*27088Sminshall if (c->dohelp) { 975*27088Sminshall printf("%s\t%s\n", c->name, c->help); 976*27088Sminshall } 977*27088Sminshall } 978*27088Sminshall } 979*27088Sminshall 980*27088Sminshall char ** 981*27088Sminshall getnexttoggle(name) 982*27088Sminshall char *name; 983*27088Sminshall { 984*27088Sminshall struct cmd *c = (struct cmd *) name; 985*27088Sminshall 986*27088Sminshall return (char **) (c+1); 987*27088Sminshall } 988*27088Sminshall 989*27088Sminshall struct cmd * 990*27088Sminshall gettoggle(name) 991*27088Sminshall char *name; 992*27088Sminshall { 993*27088Sminshall return (struct cmd *) genget(name, (char **) togglelist, getnexttoggle); 994*27088Sminshall } 995*27088Sminshall 996*27088Sminshall toggle(argc, argv) 997*27088Sminshall int argc; 998*27088Sminshall char *argv[]; 999*27088Sminshall { 1000*27088Sminshall char *name; 1001*27088Sminshall struct cmd *c; 1002*27088Sminshall 1003*27088Sminshall if (argc < 2) { 1004*27088Sminshall fprintf(stderr, 1005*27088Sminshall "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); 1006*27088Sminshall return; 1007*27088Sminshall } 1008*27088Sminshall argc--; 1009*27088Sminshall argv++; 1010*27088Sminshall while (argc--) { 1011*27088Sminshall name = *argv++; 1012*27088Sminshall c = gettoggle(name); 1013*27088Sminshall if (c == (struct cmd *) -1) { 1014*27088Sminshall fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", 1015*27088Sminshall name); 1016*27088Sminshall } else if (c == 0) { 1017*27088Sminshall fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", 1018*27088Sminshall name); 1019*27088Sminshall } else { 1020*27088Sminshall (*c->handler)(c); 1021*27088Sminshall } 1022*27088Sminshall } 1023*27088Sminshall } 1024*27088Sminshall 1025*27088Sminshall /* 1026*27088Sminshall * The following are the data structures, and many of the routines, 1027*27088Sminshall * relating to command processing. 1028*27088Sminshall */ 1029*27088Sminshall 1030*27088Sminshall /* 1031*27088Sminshall * Set the escape character. 1032*27088Sminshall */ 1033*27088Sminshall setescape(argc, argv) 1034*27088Sminshall int argc; 1035*27088Sminshall char *argv[]; 1036*27088Sminshall { 1037*27088Sminshall register char *arg; 1038*27088Sminshall char buf[50]; 1039*27088Sminshall 1040*27088Sminshall if (argc > 2) 1041*27088Sminshall arg = argv[1]; 1042*27088Sminshall else { 1043*27088Sminshall printf("new escape character: "); 1044*27088Sminshall gets(buf); 1045*27088Sminshall arg = buf; 1046*27088Sminshall } 1047*27088Sminshall if (arg[0] != '\0') 1048*27088Sminshall escape = arg[0]; 1049*27088Sminshall printf("Escape character is '%s'.\n", control(escape)); 1050*27088Sminshall fflush(stdout); 1051*27088Sminshall } 1052*27088Sminshall 1053*27088Sminshall /*VARARGS*/ 1054*27088Sminshall setcrmod() 1055*27088Sminshall { 1056*27088Sminshall 1057*27088Sminshall crmod = !crmod; 1058*27088Sminshall printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 1059*27088Sminshall fflush(stdout); 1060*27088Sminshall } 1061*27088Sminshall 1062*27088Sminshall /*VARARGS*/ 1063*27088Sminshall suspend() 1064*27088Sminshall { 1065*27088Sminshall register int save; 1066*27088Sminshall 1067*27088Sminshall save = mode(0); 1068*27088Sminshall kill(0, SIGTSTP); 1069*27088Sminshall /* reget parameters in case they were changed */ 1070*27088Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 1071*27088Sminshall ioctl(0, TIOCGETC, (char *)&otc); 1072*27088Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 1073*27088Sminshall (void) mode(save); 1074*27088Sminshall } 1075*27088Sminshall 1076*27088Sminshall /*VARARGS*/ 1077*27088Sminshall bye() 1078*27088Sminshall { 1079*27088Sminshall register char *op; 1080*27088Sminshall 1081*27088Sminshall (void) mode(0); 1082*27088Sminshall if (connected) { 1083*27088Sminshall shutdown(net, 2); 1084*27088Sminshall printf("Connection closed.\n"); 1085*27088Sminshall close(net); 1086*27088Sminshall connected = 0; 1087*27088Sminshall /* reset his options */ 1088*27088Sminshall for (op = hisopts; op < &hisopts[256]; op++) 1089*27088Sminshall *op = 0; 1090*27088Sminshall } 1091*27088Sminshall } 1092*27088Sminshall 1093*27088Sminshall /*VARARGS*/ 1094*27088Sminshall quit() 1095*27088Sminshall { 1096*27088Sminshall call(bye, "bye", 0); 1097*27088Sminshall exit(0); 1098*27088Sminshall } 1099*27088Sminshall 1100*27088Sminshall /* 1101*27088Sminshall * Print status about the connection. 1102*27088Sminshall */ 1103*27088Sminshall /*VARARGS*/ 1104*27088Sminshall status() 1105*27088Sminshall { 1106*27088Sminshall if (connected) 1107*27088Sminshall printf("Connected to %s.\n", hostname); 1108*27088Sminshall else 1109*27088Sminshall printf("No connection.\n"); 1110*27088Sminshall printf("Escape character is '%s'.\n", control(escape)); 1111*27088Sminshall fflush(stdout); 1112*27088Sminshall } 1113*27088Sminshall 1114*27088Sminshall tn(argc, argv) 1115*27088Sminshall int argc; 1116*27088Sminshall char *argv[]; 1117*27088Sminshall { 1118*27088Sminshall register int c; 1119*27088Sminshall register struct hostent *host = 0; 1120*27088Sminshall 1121*27088Sminshall if (connected) { 1122*27088Sminshall printf("?Already connected to %s\n", hostname); 1123*27088Sminshall return; 1124*27088Sminshall } 1125*27088Sminshall if (argc < 2) { 1126*27088Sminshall strcpy(line, "Connect "); 1127*27088Sminshall printf("(to) "); 1128*27088Sminshall gets(&line[strlen(line)]); 1129*27088Sminshall makeargv(); 1130*27088Sminshall argc = margc; 1131*27088Sminshall argv = margv; 1132*27088Sminshall } 1133*27088Sminshall if (argc > 3) { 1134*27088Sminshall printf("usage: %s host-name [port]\n", argv[0]); 1135*27088Sminshall return; 1136*27088Sminshall } 1137*27088Sminshall sin.sin_addr.s_addr = inet_addr(argv[1]); 1138*27088Sminshall if (sin.sin_addr.s_addr != -1) { 1139*27088Sminshall sin.sin_family = AF_INET; 1140*27088Sminshall strcpy(hnamebuf, argv[1]); 1141*27088Sminshall hostname = hnamebuf; 1142*27088Sminshall } else { 1143*27088Sminshall host = gethostbyname(argv[1]); 1144*27088Sminshall if (host) { 1145*27088Sminshall sin.sin_family = host->h_addrtype; 1146*27088Sminshall bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 1147*27088Sminshall host->h_length); 1148*27088Sminshall hostname = host->h_name; 1149*27088Sminshall } else { 1150*27088Sminshall printf("%s: unknown host\n", argv[1]); 1151*27088Sminshall return; 1152*27088Sminshall } 1153*27088Sminshall } 1154*27088Sminshall sin.sin_port = sp->s_port; 1155*27088Sminshall if (argc == 3) { 1156*27088Sminshall sin.sin_port = atoi(argv[2]); 1157*27088Sminshall if (sin.sin_port <= 0) { 1158*27088Sminshall sp = getservbyname(argv[2], "tcp"); 1159*27088Sminshall if (sp) 1160*27088Sminshall sin.sin_port = sp->s_port; 1161*27088Sminshall else { 1162*27088Sminshall printf("%s: bad port number\n", argv[2]); 1163*27088Sminshall return; 1164*27088Sminshall } 1165*27088Sminshall } else { 1166*27088Sminshall sin.sin_port = atoi(argv[2]); 1167*27088Sminshall sin.sin_port = htons(sin.sin_port); 1168*27088Sminshall } 1169*27088Sminshall telnetport = 0; 1170*27088Sminshall } 1171*27088Sminshall signal(SIGINT, intr); 1172*27088Sminshall signal(SIGPIPE, deadpeer); 1173*27088Sminshall printf("Trying...\n"); 1174*27088Sminshall do { 1175*27088Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 1176*27088Sminshall if (net < 0) { 1177*27088Sminshall perror("telnet: socket"); 1178*27088Sminshall return; 1179*27088Sminshall } 1180*27088Sminshall if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, 1181*27088Sminshall sizeof(debug)) < 0) 1182*27088Sminshall perror("setsockopt (SO_DEBUG)"); 1183*27088Sminshall if (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) { 1184*27088Sminshall if (host && host->h_addr_list[1]) { 1185*27088Sminshall int oerrno = errno; 1186*27088Sminshall 1187*27088Sminshall fprintf(stderr, 1188*27088Sminshall "telnet: connect to address %s: ", 1189*27088Sminshall inet_ntoa(sin.sin_addr)); 1190*27088Sminshall errno = oerrno; 1191*27088Sminshall perror(0); 1192*27088Sminshall host->h_addr_list++; 1193*27088Sminshall bcopy(host->h_addr_list[0], 1194*27088Sminshall (caddr_t)&sin.sin_addr, host->h_length); 1195*27088Sminshall fprintf(stderr, "Trying %s...\n", 1196*27088Sminshall inet_ntoa(sin.sin_addr)); 1197*27088Sminshall (void) close(net); 1198*27088Sminshall continue; 1199*27088Sminshall } 1200*27088Sminshall perror("telnet: connect"); 1201*27088Sminshall signal(SIGINT, SIG_DFL); 1202*27088Sminshall return; 1203*27088Sminshall } 1204*27088Sminshall connected++; 1205*27088Sminshall } while (connected == 0); 1206*27088Sminshall call(status, "status", 0); 1207*27088Sminshall if (setjmp(peerdied) == 0) 1208*27088Sminshall telnet(); 1209*27088Sminshall fprintf(stderr, "Connection closed by foreign host.\n"); 1210*27088Sminshall exit(1); 1211*27088Sminshall } 1212*27088Sminshall 1213*27088Sminshall 1214*27088Sminshall #define HELPINDENT (sizeof ("connect")) 1215*27088Sminshall 1216*27088Sminshall char openhelp[] = "connect to a site"; 1217*27088Sminshall char closehelp[] = "close current connection"; 1218*27088Sminshall char quithelp[] = "exit telnet"; 1219*27088Sminshall char zhelp[] = "suspend telnet"; 1220*27088Sminshall char escapehelp[] = "set escape character"; 1221*27088Sminshall char statushelp[] = "print status information"; 1222*27088Sminshall char helphelp[] = "print help information"; 1223*27088Sminshall char crmodhelp[] = "toggle mapping of received carriage returns"; 1224*27088Sminshall char togglestring[] = "toggle various (debugging) options"; 1225*27088Sminshall char sendhelp[] = "transmit special characters"; 1226*27088Sminshall 1227*27088Sminshall int help(); 1228*27088Sminshall 1229*27088Sminshall struct cmd cmdtab[] = { 1230*27088Sminshall { "open", openhelp, tn, 1, 0 }, 1231*27088Sminshall { "close", closehelp, bye, 1, 1 }, 1232*27088Sminshall { "quit", quithelp, quit, 1, 0 }, 1233*27088Sminshall { "z", zhelp, suspend, 1, 0 }, 1234*27088Sminshall { "escape", escapehelp, setescape, 1, 0 }, 1235*27088Sminshall { "status", statushelp, status, 1, 0 }, 1236*27088Sminshall { "crmod", crmodhelp, setcrmod, 1, 0 }, 1237*27088Sminshall { "send", sendhelp, sendcmd, 1, 1 }, 1238*27088Sminshall { "transmit", sendhelp, sendcmd, 0, 1 }, 1239*27088Sminshall { "xmit", sendhelp, sendcmd, 0, 1 }, 1240*27088Sminshall { "toggle", togglestring, toggle, 1, 0 }, 1241*27088Sminshall { "?", helphelp, help, 1, 0 }, 1242*27088Sminshall { "help", helphelp, help, 0, 0 }, 1243*27088Sminshall 0 1244*27088Sminshall }; 1245*27088Sminshall 1246*27088Sminshall 1247*27088Sminshall /* 1248*27088Sminshall * Help command. 1249*27088Sminshall */ 1250*27088Sminshall help(argc, argv) 1251*27088Sminshall int argc; 1252*27088Sminshall char *argv[]; 1253*27088Sminshall { 1254*27088Sminshall register struct cmd *c; 1255*27088Sminshall 1256*27088Sminshall if (argc == 1) { 1257*27088Sminshall printf("Commands may be abbreviated. Commands are:\n\n"); 1258*27088Sminshall for (c = cmdtab; c->name; c++) 1259*27088Sminshall if (c->dohelp) { 1260*27088Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 1261*27088Sminshall c->help); 1262*27088Sminshall } 1263*27088Sminshall return; 1264*27088Sminshall } 1265*27088Sminshall while (--argc > 0) { 1266*27088Sminshall register char *arg; 1267*27088Sminshall arg = *++argv; 1268*27088Sminshall c = getcmd(arg); 1269*27088Sminshall if (c == (struct cmd *)-1) 1270*27088Sminshall printf("?Ambiguous help command %s\n", arg); 1271*27088Sminshall else if (c == (struct cmd *)0) 1272*27088Sminshall printf("?Invalid help command %s\n", arg); 1273*27088Sminshall else 1274*27088Sminshall printf("%s\n", c->help); 1275*27088Sminshall } 1276*27088Sminshall } 1277*27088Sminshall /* 1278*27088Sminshall * Call routine with argc, argv set from args (terminated by 0). 1279*27088Sminshall * VARARGS2 1280*27088Sminshall */ 1281*27088Sminshall call(routine, args) 1282*27088Sminshall int (*routine)(); 1283*27088Sminshall int args; 1284*27088Sminshall { 1285*27088Sminshall register int *argp; 1286*27088Sminshall register int argc; 1287*27088Sminshall 1288*27088Sminshall for (argc = 0, argp = &args; *argp++ != 0; argc++) 1289*27088Sminshall ; 1290*27088Sminshall (*routine)(argc, &args); 1291*27088Sminshall } 1292*27088Sminshall 1293*27088Sminshall makeargv() 1294*27088Sminshall { 1295*27088Sminshall register char *cp; 1296*27088Sminshall register char **argp = margv; 1297*27088Sminshall 1298*27088Sminshall margc = 0; 1299*27088Sminshall for (cp = line; *cp;) { 1300*27088Sminshall while (isspace(*cp)) 1301*27088Sminshall cp++; 1302*27088Sminshall if (*cp == '\0') 1303*27088Sminshall break; 1304*27088Sminshall *argp++ = cp; 1305*27088Sminshall margc += 1; 1306*27088Sminshall while (*cp != '\0' && !isspace(*cp)) 1307*27088Sminshall cp++; 1308*27088Sminshall if (*cp == '\0') 1309*27088Sminshall break; 1310*27088Sminshall *cp++ = '\0'; 1311*27088Sminshall } 1312*27088Sminshall *argp++ = 0; 1313*27088Sminshall } 1314*27088Sminshall 1315*27088Sminshall char ** 1316*27088Sminshall getnextcmd(name) 1317*27088Sminshall char *name; 1318*27088Sminshall { 1319*27088Sminshall struct cmd *c = (struct cmd *) name; 1320*27088Sminshall 1321*27088Sminshall return (char **) (c+1); 1322*27088Sminshall } 1323*27088Sminshall 1324*27088Sminshall struct cmd * 1325*27088Sminshall getcmd(name) 1326*27088Sminshall char *name; 1327*27088Sminshall { 1328*27088Sminshall return (struct cmd *) genget(name, (char **) cmdtab, getnextcmd); 1329*27088Sminshall } 1330*27088Sminshall 1331*27088Sminshall command(top) 1332*27088Sminshall int top; 1333*27088Sminshall { 1334*27088Sminshall register struct cmd *c; 1335*27088Sminshall int oldmode, wasopen; 1336*27088Sminshall 1337*27088Sminshall oldmode = mode(0); 1338*27088Sminshall if (!top) 1339*27088Sminshall putchar('\n'); 1340*27088Sminshall else 1341*27088Sminshall signal(SIGINT, SIG_DFL); 1342*27088Sminshall for (;;) { 1343*27088Sminshall printf("%s> ", prompt); 1344*27088Sminshall if (gets(line) == 0) { 1345*27088Sminshall if (feof(stdin)) 1346*27088Sminshall quit(); 1347*27088Sminshall break; 1348*27088Sminshall } 1349*27088Sminshall if (line[0] == 0) 1350*27088Sminshall break; 1351*27088Sminshall makeargv(); 1352*27088Sminshall c = getcmd(margv[0]); 1353*27088Sminshall if (c == (struct cmd *)-1) { 1354*27088Sminshall printf("?Ambiguous command\n"); 1355*27088Sminshall continue; 1356*27088Sminshall } 1357*27088Sminshall if (c == 0) { 1358*27088Sminshall printf("?Invalid command\n"); 1359*27088Sminshall continue; 1360*27088Sminshall } 1361*27088Sminshall if (c->needconnect && !connected) { 1362*27088Sminshall printf("?Need to be connected first.\n"); 1363*27088Sminshall continue; 1364*27088Sminshall } 1365*27088Sminshall (*c->handler)(margc, margv); 1366*27088Sminshall if (c->handler != help) 1367*27088Sminshall break; 1368*27088Sminshall } 1369*27088Sminshall if (!top) { 1370*27088Sminshall if (!connected) 1371*27088Sminshall longjmp(toplevel, 1); 1372*27088Sminshall (void) mode(oldmode); 1373*27088Sminshall } 1374*27088Sminshall } 1375