111758Ssam #ifndef lint 2*17922Sralph static char sccsid[] = "@(#)telnet.c 4.27 (Berkeley) 02/05/85"; 311758Ssam #endif 411758Ssam 56000Sroot /* 66000Sroot * User telnet program. 76000Sroot */ 89217Ssam #include <sys/types.h> 99217Ssam #include <sys/socket.h> 109972Ssam #include <sys/ioctl.h> 119217Ssam 129217Ssam #include <netinet/in.h> 139217Ssam 1412212Ssam #define TELOPTS 1512212Ssam #include <arpa/telnet.h> 1612212Ssam 176000Sroot #include <stdio.h> 186000Sroot #include <ctype.h> 196000Sroot #include <errno.h> 206000Sroot #include <signal.h> 216000Sroot #include <setjmp.h> 228345Ssam #include <netdb.h> 239217Ssam 246000Sroot #define strip(x) ((x)&0177) 256000Sroot 266000Sroot char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; 278378Ssam char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 286000Sroot 296000Sroot char hisopts[256]; 306000Sroot char myopts[256]; 316000Sroot 326000Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 336000Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 346000Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 356000Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 366000Sroot 376000Sroot int connected; 386000Sroot int net; 399972Ssam int showoptions = 0; 407377Sfeldman int options; 4110339Ssam int debug = 0; 429972Ssam int crmod = 0; 436000Sroot char *prompt; 449972Ssam char escape = CTRL(]); 456000Sroot 466000Sroot char line[200]; 476000Sroot int margc; 486000Sroot char *margv[20]; 496000Sroot 506000Sroot jmp_buf toplevel; 516000Sroot jmp_buf peerdied; 526000Sroot 536000Sroot extern int errno; 546000Sroot 556000Sroot int tn(), quit(), suspend(), bye(), help(); 566024Ssam int setescape(), status(), toggle(), setoptions(); 57*17922Sralph int setcrmod(), setdebug(), sendesc(), ayt(), intp(); 586000Sroot 598378Ssam #define HELPINDENT (sizeof ("connect")) 606000Sroot 616000Sroot struct cmd { 6211758Ssam char *name; /* command name */ 6311758Ssam char *help; /* help string */ 6411758Ssam int (*handler)(); /* routine which executes command */ 656000Sroot }; 666000Sroot 6711758Ssam char openhelp[] = "connect to a site"; 6811758Ssam char closehelp[] = "close current connection"; 6911758Ssam char quithelp[] = "exit telnet"; 7011758Ssam char zhelp[] = "suspend telnet"; 7111758Ssam char debughelp[] = "toggle debugging"; 7211758Ssam char escapehelp[] = "set escape character"; 7311758Ssam char statushelp[] = "print status information"; 7411758Ssam char helphelp[] = "print help information"; 7511758Ssam char optionshelp[] = "toggle viewing of options processing"; 7611758Ssam char crmodhelp[] = "toggle mapping of received carriage returns"; 77*17922Sralph char sendeschelp[] = "send escape character"; 78*17922Sralph char aythelp[] = "send Are You There"; 79*17922Sralph char intphelp[] = "send Interrupt Process"; 806000Sroot 816000Sroot struct cmd cmdtab[] = { 8211758Ssam { "open", openhelp, tn }, 8311758Ssam { "close", closehelp, bye }, 8411758Ssam { "quit", quithelp, quit }, 856000Sroot { "z", zhelp, suspend }, 8611758Ssam { "escape", escapehelp, setescape }, 8711758Ssam { "status", statushelp, status }, 8811758Ssam { "options", optionshelp, setoptions }, 8911758Ssam { "crmod", crmodhelp, setcrmod }, 9011758Ssam { "debug", debughelp, setdebug }, 91*17922Sralph { "ayt", aythelp, ayt }, 92*17922Sralph { "interrupt", intphelp, intp }, 93*17922Sralph { "passthru", sendeschelp, sendesc }, 9411758Ssam { "?", helphelp, help }, 956000Sroot 0 966000Sroot }; 976000Sroot 989972Ssam struct sockaddr_in sin; 996000Sroot 1006000Sroot int intr(), deadpeer(); 1016000Sroot char *control(); 1026000Sroot struct cmd *getcmd(); 1038345Ssam struct servent *sp; 1046000Sroot 10513076Ssam struct tchars otc; 10613076Ssam struct ltchars oltc; 10713076Ssam struct sgttyb ottyb; 1088378Ssam 1096000Sroot main(argc, argv) 1106000Sroot int argc; 1116000Sroot char *argv[]; 1126000Sroot { 1138345Ssam sp = getservbyname("telnet", "tcp"); 1148345Ssam if (sp == 0) { 1158345Ssam fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 1168345Ssam exit(1); 1178345Ssam } 11813076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 11913076Ssam ioctl(0, TIOCGETC, (char *)&otc); 12013076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 1216000Sroot setbuf(stdin, 0); 1226000Sroot setbuf(stdout, 0); 1236000Sroot prompt = argv[0]; 12417484Sleres if (argc > 1 && !strcmp(argv[1], "-d")) { 12517484Sleres debug = 1; 12617484Sleres argv++; 12717484Sleres argc--; 12817484Sleres } 1296000Sroot if (argc != 1) { 1306000Sroot if (setjmp(toplevel) != 0) 1316000Sroot exit(0); 1326000Sroot tn(argc, argv); 1336000Sroot } 1346000Sroot setjmp(toplevel); 1356000Sroot for (;;) 1366000Sroot command(1); 1376000Sroot } 1386000Sroot 1398377Ssam char *hostname; 1408377Ssam char hnamebuf[32]; 1416000Sroot 1426000Sroot tn(argc, argv) 1436000Sroot int argc; 1446000Sroot char *argv[]; 1456000Sroot { 1466000Sroot register int c; 1478377Ssam register struct hostent *host; 1486000Sroot 1496000Sroot if (connected) { 1508377Ssam printf("?Already connected to %s\n", hostname); 1516000Sroot return; 1526000Sroot } 1536000Sroot if (argc < 2) { 1546000Sroot strcpy(line, "Connect "); 1556000Sroot printf("(to) "); 1566000Sroot gets(&line[strlen(line)]); 1576000Sroot makeargv(); 1586000Sroot argc = margc; 1596000Sroot argv = margv; 1606000Sroot } 1616000Sroot if (argc > 3) { 1626000Sroot printf("usage: %s host-name [port]\n", argv[0]); 1636000Sroot return; 1646000Sroot } 1658345Ssam host = gethostbyname(argv[1]); 1668377Ssam if (host) { 1679217Ssam sin.sin_family = host->h_addrtype; 1689217Ssam bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length); 1698377Ssam hostname = host->h_name; 1708377Ssam } else { 1719217Ssam sin.sin_family = AF_INET; 1728377Ssam sin.sin_addr.s_addr = inet_addr(argv[1]); 1738377Ssam if (sin.sin_addr.s_addr == -1) { 1748377Ssam printf("%s: unknown host\n", argv[1]); 1758377Ssam return; 1768377Ssam } 1778377Ssam strcpy(hnamebuf, argv[1]); 1788377Ssam hostname = hnamebuf; 1796000Sroot } 1808345Ssam sin.sin_port = sp->s_port; 1816024Ssam if (argc == 3) { 1826024Ssam sin.sin_port = atoi(argv[2]); 1836024Ssam if (sin.sin_port < 0) { 1846024Ssam printf("%s: bad port number\n", argv[2]); 1856024Ssam return; 1866024Ssam } 1879968Ssam sin.sin_port = htons(sin.sin_port); 1886024Ssam } 189*17922Sralph net = socket(AF_INET, SOCK_STREAM, 0); 1909217Ssam if (net < 0) { 1919217Ssam perror("telnet: socket"); 1926000Sroot return; 1936000Sroot } 19417484Sleres if (debug && 19517484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 19611758Ssam perror("setsockopt (SO_DEBUG)"); 19712989Ssam signal(SIGINT, intr); 19812989Ssam signal(SIGPIPE, deadpeer); 1996000Sroot printf("Trying...\n"); 200*17922Sralph if (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) { 2019217Ssam perror("telnet: connect"); 20212989Ssam signal(SIGINT, SIG_DFL); 2036000Sroot return; 2046000Sroot } 2056000Sroot connected++; 2066000Sroot call(status, "status", 0); 2076000Sroot if (setjmp(peerdied) == 0) 2086000Sroot telnet(net); 2096000Sroot fprintf(stderr, "Connection closed by foreign host.\n"); 2106000Sroot exit(1); 2116000Sroot } 2126000Sroot 2136000Sroot /* 2146000Sroot * Print status about the connection. 2156000Sroot */ 2166000Sroot /*VARARGS*/ 2176000Sroot status() 2186000Sroot { 2196000Sroot if (connected) 2208377Ssam printf("Connected to %s.\n", hostname); 2216000Sroot else 2226000Sroot printf("No connection.\n"); 2236000Sroot printf("Escape character is '%s'.\n", control(escape)); 2249972Ssam fflush(stdout); 2256000Sroot } 2266000Sroot 2276000Sroot makeargv() 2286000Sroot { 2296000Sroot register char *cp; 2306000Sroot register char **argp = margv; 2316000Sroot 2326000Sroot margc = 0; 2336000Sroot for (cp = line; *cp;) { 2346000Sroot while (isspace(*cp)) 2356000Sroot cp++; 2366000Sroot if (*cp == '\0') 2376000Sroot break; 2386000Sroot *argp++ = cp; 2396000Sroot margc += 1; 2406000Sroot while (*cp != '\0' && !isspace(*cp)) 2416000Sroot cp++; 2426000Sroot if (*cp == '\0') 2436000Sroot break; 2446000Sroot *cp++ = '\0'; 2456000Sroot } 2466000Sroot *argp++ = 0; 2476000Sroot } 2486000Sroot 2496000Sroot /*VARARGS*/ 2506000Sroot suspend() 2516000Sroot { 2526000Sroot register int save; 2536000Sroot 2546000Sroot save = mode(0); 2558378Ssam kill(0, SIGTSTP); 2568378Ssam /* reget parameters in case they were changed */ 25713076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 25813076Ssam ioctl(0, TIOCGETC, (char *)&otc); 25913076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 2608378Ssam (void) mode(save); 2616000Sroot } 2626000Sroot 2636000Sroot /*VARARGS*/ 2646000Sroot bye() 2656000Sroot { 2668378Ssam register char *op; 2676000Sroot 2688378Ssam (void) mode(0); 2696000Sroot if (connected) { 27011758Ssam shutdown(net, 2); 2716000Sroot printf("Connection closed.\n"); 2726000Sroot close(net); 2736000Sroot connected = 0; 2748378Ssam /* reset his options */ 2758378Ssam for (op = hisopts; op < &hisopts[256]; op++) 2768378Ssam *op = 0; 2776000Sroot } 2786000Sroot } 2796000Sroot 2806000Sroot /*VARARGS*/ 2816000Sroot quit() 2826000Sroot { 2836000Sroot call(bye, "bye", 0); 2846000Sroot exit(0); 2856000Sroot } 2866000Sroot 2876000Sroot /* 2886000Sroot * Help command. 2896000Sroot */ 2906000Sroot help(argc, argv) 2916000Sroot int argc; 2926000Sroot char *argv[]; 2936000Sroot { 2946000Sroot register struct cmd *c; 2956000Sroot 2966000Sroot if (argc == 1) { 2976000Sroot printf("Commands may be abbreviated. Commands are:\n\n"); 2986000Sroot for (c = cmdtab; c->name; c++) 2996000Sroot printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 3006000Sroot return; 3016000Sroot } 3026000Sroot while (--argc > 0) { 3036000Sroot register char *arg; 3046000Sroot arg = *++argv; 3056000Sroot c = getcmd(arg); 3066000Sroot if (c == (struct cmd *)-1) 3076000Sroot printf("?Ambiguous help command %s\n", arg); 3086000Sroot else if (c == (struct cmd *)0) 3096000Sroot printf("?Invalid help command %s\n", arg); 3106000Sroot else 3116000Sroot printf("%s\n", c->help); 3126000Sroot } 3136000Sroot } 3146000Sroot 3156000Sroot /* 3166000Sroot * Call routine with argc, argv set from args (terminated by 0). 3176000Sroot * VARARGS2 3186000Sroot */ 3196000Sroot call(routine, args) 3206000Sroot int (*routine)(); 3216000Sroot int args; 3226000Sroot { 3236000Sroot register int *argp; 3246000Sroot register int argc; 3256000Sroot 3266000Sroot for (argc = 0, argp = &args; *argp++ != 0; argc++) 3276000Sroot ; 3286000Sroot (*routine)(argc, &args); 3296000Sroot } 3306000Sroot 33113076Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 33213076Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3339972Ssam 3346000Sroot mode(f) 3356000Sroot register int f; 3366000Sroot { 3378378Ssam static int prevmode = 0; 33813076Ssam struct tchars *tc; 33913076Ssam struct ltchars *ltc; 34013076Ssam struct sgttyb sb; 34113076Ssam int onoff, old; 3426000Sroot 3438378Ssam if (prevmode == f) 3448378Ssam return (f); 3458378Ssam old = prevmode; 3468378Ssam prevmode = f; 34713076Ssam sb = ottyb; 3486000Sroot switch (f) { 3498378Ssam 3506000Sroot case 0: 3516000Sroot onoff = 0; 3529972Ssam tc = &otc; 35313076Ssam ltc = &oltc; 3546000Sroot break; 3556000Sroot 3566000Sroot case 1: 3576000Sroot case 2: 35813076Ssam sb.sg_flags |= CBREAK; 3598378Ssam if (f == 1) 36013076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 3618378Ssam else 36213076Ssam sb.sg_flags |= ECHO|CRMOD; 36313076Ssam sb.sg_erase = sb.sg_kill = -1; 3649972Ssam tc = ¬c; 36513076Ssam ltc = &noltc; 3666000Sroot onoff = 1; 3679972Ssam break; 3689972Ssam 3699972Ssam default: 3709972Ssam return; 3716000Sroot } 37213076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 37313076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 37413076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 3756000Sroot ioctl(fileno(stdin), FIONBIO, &onoff); 3766000Sroot ioctl(fileno(stdout), FIONBIO, &onoff); 3776000Sroot return (old); 3786000Sroot } 3796000Sroot 3806000Sroot char sibuf[BUFSIZ], *sbp; 3816000Sroot char tibuf[BUFSIZ], *tbp; 3826000Sroot int scc, tcc; 3836000Sroot 3846000Sroot /* 3856000Sroot * Select from tty and network... 3866000Sroot */ 3876000Sroot telnet(s) 3886000Sroot int s; 3896000Sroot { 3906000Sroot register int c; 3916000Sroot int tin = fileno(stdin), tout = fileno(stdout); 3926000Sroot int on = 1; 3936000Sroot 3948378Ssam (void) mode(2); 3956000Sroot ioctl(s, FIONBIO, &on); 396*17922Sralph if (!hisopts[TELOPT_SGA]) 397*17922Sralph willoption(TELOPT_SGA); 3986000Sroot for (;;) { 3996000Sroot int ibits = 0, obits = 0; 4006000Sroot 4016000Sroot if (nfrontp - nbackp) 4026000Sroot obits |= (1 << s); 4036000Sroot else 4046000Sroot ibits |= (1 << tin); 4056000Sroot if (tfrontp - tbackp) 4066000Sroot obits |= (1 << tout); 4076000Sroot else 4086000Sroot ibits |= (1 << s); 4096000Sroot if (scc < 0 && tcc < 0) 4106000Sroot break; 4119217Ssam select(16, &ibits, &obits, 0, 0); 4126000Sroot if (ibits == 0 && obits == 0) { 4136000Sroot sleep(5); 4146000Sroot continue; 4156000Sroot } 4166000Sroot 4176000Sroot /* 4186000Sroot * Something to read from the network... 4196000Sroot */ 4206000Sroot if (ibits & (1 << s)) { 4218378Ssam scc = read(s, sibuf, sizeof (sibuf)); 4226000Sroot if (scc < 0 && errno == EWOULDBLOCK) 4236000Sroot scc = 0; 4246000Sroot else { 4256000Sroot if (scc <= 0) 4266000Sroot break; 4276000Sroot sbp = sibuf; 4286000Sroot } 4296000Sroot } 4306000Sroot 4316000Sroot /* 4326000Sroot * Something to read from the tty... 4336000Sroot */ 4346000Sroot if (ibits & (1 << tin)) { 4358378Ssam tcc = read(tin, tibuf, sizeof (tibuf)); 4366000Sroot if (tcc < 0 && errno == EWOULDBLOCK) 4376000Sroot tcc = 0; 4386000Sroot else { 4396000Sroot if (tcc <= 0) 4406000Sroot break; 4416000Sroot tbp = tibuf; 4426000Sroot } 4436000Sroot } 4446000Sroot 4456000Sroot while (tcc > 0) { 4466000Sroot register int c; 4476000Sroot 4486000Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 4496000Sroot break; 4506000Sroot c = *tbp++ & 0377, tcc--; 4516000Sroot if (strip(c) == escape) { 4526000Sroot command(0); 4536000Sroot tcc = 0; 4546000Sroot break; 4556000Sroot } 456*17922Sralph switch (c) { 457*17922Sralph case '\n': 458*17922Sralph if (!hisopts[TELOPT_ECHO]) 459*17922Sralph *nfrontp++ = '\r'; 460*17922Sralph *nfrontp++ = '\n'; 461*17922Sralph break; 462*17922Sralph case '\r': 463*17922Sralph *nfrontp++ = '\r'; 464*17922Sralph if (hisopts[TELOPT_ECHO]) 465*17922Sralph *nfrontp++ = '\n'; 466*17922Sralph else 467*17922Sralph *nfrontp++ = '\0'; 468*17922Sralph break; 469*17922Sralph case IAC: 470*17922Sralph *nfrontp++ = IAC; 471*17922Sralph /* fall into ... */ 472*17922Sralph default: 47311758Ssam *nfrontp++ = c; 474*17922Sralph break; 475*17922Sralph } 4766000Sroot } 4776000Sroot if ((obits & (1 << s)) && (nfrontp - nbackp) > 0) 4786000Sroot netflush(s); 4796000Sroot if (scc > 0) 4806000Sroot telrcv(); 4816000Sroot if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0) 4826000Sroot ttyflush(tout); 4836000Sroot } 4848378Ssam (void) mode(0); 4856000Sroot } 4866000Sroot 4876000Sroot command(top) 4886000Sroot int top; 4896000Sroot { 4906000Sroot register struct cmd *c; 4916000Sroot int oldmode, wasopen; 4926000Sroot 4936000Sroot oldmode = mode(0); 4946000Sroot if (!top) 4956000Sroot putchar('\n'); 4966000Sroot else 49712989Ssam signal(SIGINT, SIG_DFL); 4986000Sroot for (;;) { 4996000Sroot printf("%s> ", prompt); 50013997Ssam if (gets(line) == 0) { 50113997Ssam if (feof(stdin)) { 50213997Ssam clearerr(stdin); 50313997Ssam putchar('\n'); 50413997Ssam } 5056000Sroot break; 50613997Ssam } 5076000Sroot if (line[0] == 0) 5086000Sroot break; 5096000Sroot makeargv(); 5106000Sroot c = getcmd(margv[0]); 5116000Sroot if (c == (struct cmd *)-1) { 5126000Sroot printf("?Ambiguous command\n"); 5136000Sroot continue; 5146000Sroot } 5156000Sroot if (c == 0) { 5166000Sroot printf("?Invalid command\n"); 5176000Sroot continue; 5186000Sroot } 5196000Sroot (*c->handler)(margc, margv); 5206000Sroot if (c->handler != help) 5216000Sroot break; 5226000Sroot } 5236000Sroot if (!top) { 5246000Sroot if (!connected) 5256000Sroot longjmp(toplevel, 1); 5268378Ssam (void) mode(oldmode); 5276000Sroot } 5286000Sroot } 5296000Sroot 5306000Sroot /* 5316000Sroot * Telnet receiver states for fsm 5326000Sroot */ 5336000Sroot #define TS_DATA 0 5346000Sroot #define TS_IAC 1 5356000Sroot #define TS_WILL 2 5366000Sroot #define TS_WONT 3 5376000Sroot #define TS_DO 4 5386000Sroot #define TS_DONT 5 5396000Sroot 5406000Sroot telrcv() 5416000Sroot { 5426000Sroot register int c; 5436000Sroot static int state = TS_DATA; 5446000Sroot 5456000Sroot while (scc > 0) { 5466000Sroot c = *sbp++ & 0377, scc--; 5476000Sroot switch (state) { 5486000Sroot 5496000Sroot case TS_DATA: 5509972Ssam if (c == IAC) { 5516000Sroot state = TS_IAC; 5529972Ssam continue; 5539972Ssam } 5549972Ssam *tfrontp++ = c; 5559972Ssam /* 5569972Ssam * This hack is needed since we can't set 5579972Ssam * CRMOD on output only. Machines like MULTICS 5589972Ssam * like to send \r without \n; since we must 5599972Ssam * turn off CRMOD to get proper input, the mapping 5609972Ssam * is done here (sigh). 5619972Ssam */ 5629972Ssam if (c == '\r' && crmod) 5639972Ssam *tfrontp++ = '\n'; 5646000Sroot continue; 5656000Sroot 5666000Sroot case TS_IAC: 5676000Sroot switch (c) { 5686000Sroot 5696000Sroot case WILL: 5706000Sroot state = TS_WILL; 5716000Sroot continue; 5726000Sroot 5736000Sroot case WONT: 5746000Sroot state = TS_WONT; 5756000Sroot continue; 5766000Sroot 5776000Sroot case DO: 5786000Sroot state = TS_DO; 5796000Sroot continue; 5806000Sroot 5816000Sroot case DONT: 5826000Sroot state = TS_DONT; 5836000Sroot continue; 5846000Sroot 5856000Sroot case DM: 5866000Sroot ioctl(fileno(stdout), TIOCFLUSH, 0); 5876000Sroot break; 5886000Sroot 5896000Sroot case NOP: 5906000Sroot case GA: 5916000Sroot break; 5926000Sroot 5936000Sroot default: 5946000Sroot break; 5956000Sroot } 5966000Sroot state = TS_DATA; 5976000Sroot continue; 5986000Sroot 5996000Sroot case TS_WILL: 6008345Ssam printoption("RCVD", will, c, !hisopts[c]); 6016000Sroot if (!hisopts[c]) 6026000Sroot willoption(c); 6036000Sroot state = TS_DATA; 6046000Sroot continue; 6056000Sroot 6066000Sroot case TS_WONT: 6078345Ssam printoption("RCVD", wont, c, hisopts[c]); 6086000Sroot if (hisopts[c]) 6096000Sroot wontoption(c); 6106000Sroot state = TS_DATA; 6116000Sroot continue; 6126000Sroot 6136000Sroot case TS_DO: 6148345Ssam printoption("RCVD", doopt, c, !myopts[c]); 6156000Sroot if (!myopts[c]) 6166000Sroot dooption(c); 6176000Sroot state = TS_DATA; 6186000Sroot continue; 6196000Sroot 6206000Sroot case TS_DONT: 6218345Ssam printoption("RCVD", dont, c, myopts[c]); 6226000Sroot if (myopts[c]) { 6236000Sroot myopts[c] = 0; 6246000Sroot sprintf(nfrontp, wont, c); 6258378Ssam nfrontp += sizeof (wont) - 2; 6268345Ssam printoption("SENT", wont, c); 6276000Sroot } 6286000Sroot state = TS_DATA; 6296000Sroot continue; 6306000Sroot } 6316000Sroot } 6326000Sroot } 6336000Sroot 6346000Sroot willoption(option) 6356000Sroot int option; 6366000Sroot { 6376000Sroot char *fmt; 6386000Sroot 6396000Sroot switch (option) { 6406000Sroot 6416000Sroot case TELOPT_ECHO: 6428378Ssam (void) mode(1); 6436000Sroot 6446000Sroot case TELOPT_SGA: 6456000Sroot hisopts[option] = 1; 6466000Sroot fmt = doopt; 6476000Sroot break; 6486000Sroot 6496000Sroot case TELOPT_TM: 6506000Sroot fmt = dont; 6516000Sroot break; 6526000Sroot 6536000Sroot default: 6546000Sroot fmt = dont; 6556000Sroot break; 6566000Sroot } 6576024Ssam sprintf(nfrontp, fmt, option); 6588378Ssam nfrontp += sizeof (dont) - 2; 6598345Ssam printoption("SENT", fmt, option); 6606000Sroot } 6616000Sroot 6626000Sroot wontoption(option) 6636000Sroot int option; 6646000Sroot { 6656000Sroot char *fmt; 6666000Sroot 6676000Sroot switch (option) { 6686000Sroot 6696000Sroot case TELOPT_ECHO: 6708378Ssam (void) mode(2); 6716000Sroot 6726000Sroot case TELOPT_SGA: 6736000Sroot hisopts[option] = 0; 6746000Sroot fmt = dont; 6756000Sroot break; 6766000Sroot 6776000Sroot default: 6786000Sroot fmt = dont; 6796000Sroot } 6806000Sroot sprintf(nfrontp, fmt, option); 6818378Ssam nfrontp += sizeof (doopt) - 2; 6828345Ssam printoption("SENT", fmt, option); 6836000Sroot } 6846000Sroot 6856000Sroot dooption(option) 6866000Sroot int option; 6876000Sroot { 6886000Sroot char *fmt; 6896000Sroot 6906000Sroot switch (option) { 6916000Sroot 6926000Sroot case TELOPT_TM: 6936000Sroot fmt = wont; 6946000Sroot break; 6956000Sroot 69613231Ssam case TELOPT_ECHO: 69713231Ssam (void) mode(2); 69813231Ssam fmt = will; 69913231Ssam hisopts[option] = 0; 70013231Ssam break; 70113231Ssam 7026000Sroot case TELOPT_SGA: 7036000Sroot fmt = will; 7046000Sroot break; 7056000Sroot 7066000Sroot default: 7076000Sroot fmt = wont; 7086000Sroot break; 7096000Sroot } 7106000Sroot sprintf(nfrontp, fmt, option); 7118378Ssam nfrontp += sizeof (doopt) - 2; 7128345Ssam printoption("SENT", fmt, option); 7136000Sroot } 7146000Sroot 7156000Sroot /* 7166000Sroot * Set the escape character. 7176000Sroot */ 7186000Sroot setescape(argc, argv) 7196000Sroot int argc; 7206000Sroot char *argv[]; 7216000Sroot { 7226000Sroot register char *arg; 7236000Sroot char buf[50]; 7246000Sroot 7256000Sroot if (argc > 2) 7266000Sroot arg = argv[1]; 7276000Sroot else { 7286000Sroot printf("new escape character: "); 7296000Sroot gets(buf); 7306000Sroot arg = buf; 7316000Sroot } 7326000Sroot if (arg[0] != '\0') 7336000Sroot escape = arg[0]; 7346000Sroot printf("Escape character is '%s'.\n", control(escape)); 7359972Ssam fflush(stdout); 7366000Sroot } 7376000Sroot 7386024Ssam /*VARARGS*/ 7396024Ssam setoptions() 7406024Ssam { 7419972Ssam 7426024Ssam showoptions = !showoptions; 7436024Ssam printf("%s show option processing.\n", showoptions ? "Will" : "Wont"); 7449972Ssam fflush(stdout); 7456024Ssam } 7466024Ssam 7479972Ssam /*VARARGS*/ 7489972Ssam setcrmod() 7499972Ssam { 7509972Ssam 7519972Ssam crmod = !crmod; 7529972Ssam printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont"); 7539972Ssam fflush(stdout); 7549972Ssam } 7559972Ssam 75610339Ssam /*VARARGS*/ 75710339Ssam setdebug() 75810339Ssam { 75910339Ssam 76017484Sleres debug = debug ? 0 : 1; 76110339Ssam printf("%s turn on socket level debugging.\n", 76210339Ssam debug ? "Will" : "Wont"); 76310339Ssam fflush(stdout); 76417484Sleres if (net > 0 && 76517484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 76611758Ssam perror("setsockopt (SO_DEBUG)"); 76710339Ssam } 76810339Ssam 769*17922Sralph sendesc() 770*17922Sralph { 771*17922Sralph *nfrontp++ = escape; 772*17922Sralph } 773*17922Sralph 774*17922Sralph ayt() 775*17922Sralph { 776*17922Sralph *nfrontp++ = IAC; 777*17922Sralph *nfrontp++ = AYT; 778*17922Sralph } 779*17922Sralph 780*17922Sralph intp() 781*17922Sralph { 782*17922Sralph *nfrontp++ = IAC; 783*17922Sralph *nfrontp++ = IP; 784*17922Sralph } 785*17922Sralph 7866000Sroot /* 7876000Sroot * Construct a control character sequence 7886000Sroot * for a special character. 7896000Sroot */ 7906000Sroot char * 7916000Sroot control(c) 7926000Sroot register int c; 7936000Sroot { 7946000Sroot static char buf[3]; 7956000Sroot 7966000Sroot if (c == 0177) 7976000Sroot return ("^?"); 7986000Sroot if (c >= 040) { 7996000Sroot buf[0] = c; 8006000Sroot buf[1] = 0; 8016000Sroot } else { 8026000Sroot buf[0] = '^'; 8036000Sroot buf[1] = '@'+c; 8046000Sroot buf[2] = 0; 8056000Sroot } 8066000Sroot return (buf); 8076000Sroot } 8086000Sroot 8096000Sroot struct cmd * 8106000Sroot getcmd(name) 8116000Sroot register char *name; 8126000Sroot { 8136000Sroot register char *p, *q; 8146000Sroot register struct cmd *c, *found; 8156000Sroot register int nmatches, longest; 8166000Sroot 8176000Sroot longest = 0; 8186000Sroot nmatches = 0; 8196000Sroot found = 0; 8206000Sroot for (c = cmdtab; p = c->name; c++) { 8216000Sroot for (q = name; *q == *p++; q++) 8226000Sroot if (*q == 0) /* exact match? */ 8236000Sroot return (c); 8246000Sroot if (!*q) { /* the name was a prefix */ 8256000Sroot if (q - name > longest) { 8266000Sroot longest = q - name; 8276000Sroot nmatches = 1; 8286000Sroot found = c; 8296000Sroot } else if (q - name == longest) 8306000Sroot nmatches++; 8316000Sroot } 8326000Sroot } 8336000Sroot if (nmatches > 1) 8346000Sroot return ((struct cmd *)-1); 8356000Sroot return (found); 8366000Sroot } 8376000Sroot 8386000Sroot deadpeer() 8396000Sroot { 8408378Ssam (void) mode(0); 8416000Sroot longjmp(peerdied, -1); 8426000Sroot } 8436000Sroot 8446000Sroot intr() 8456000Sroot { 8468378Ssam (void) mode(0); 8476000Sroot longjmp(toplevel, -1); 8486000Sroot } 8496000Sroot 8506000Sroot ttyflush(fd) 8516000Sroot { 8526000Sroot int n; 8536000Sroot 8546000Sroot if ((n = tfrontp - tbackp) > 0) 8556000Sroot n = write(fd, tbackp, n); 8568345Ssam if (n < 0) 8578345Ssam return; 8586000Sroot tbackp += n; 8596000Sroot if (tbackp == tfrontp) 8606000Sroot tbackp = tfrontp = ttyobuf; 8616000Sroot } 8626000Sroot 8636000Sroot netflush(fd) 8646000Sroot { 8656000Sroot int n; 8666000Sroot 8676000Sroot if ((n = nfrontp - nbackp) > 0) 8686000Sroot n = write(fd, nbackp, n); 8696501Ssam if (n < 0) { 8706501Ssam if (errno != ENOBUFS && errno != EWOULDBLOCK) { 8718378Ssam (void) mode(0); 8728377Ssam perror(hostname); 8736501Ssam close(fd); 8746501Ssam longjmp(peerdied, -1); 8756501Ssam /*NOTREACHED*/ 8766501Ssam } 8776000Sroot n = 0; 8786501Ssam } 8796000Sroot nbackp += n; 8806000Sroot if (nbackp == nfrontp) 8816000Sroot nbackp = nfrontp = netobuf; 8826000Sroot } 8836024Ssam 8846293Sroot /*VARARGS*/ 8856293Sroot printoption(direction, fmt, option, what) 8866024Ssam char *direction, *fmt; 8876293Sroot int option, what; 8886024Ssam { 8898345Ssam if (!showoptions) 8908345Ssam return; 8916024Ssam printf("%s ", direction); 8926024Ssam if (fmt == doopt) 8936024Ssam fmt = "do"; 8946024Ssam else if (fmt == dont) 8956024Ssam fmt = "dont"; 8966024Ssam else if (fmt == will) 8976024Ssam fmt = "will"; 8986024Ssam else if (fmt == wont) 8996024Ssam fmt = "wont"; 9006024Ssam else 9016024Ssam fmt = "???"; 9026024Ssam if (option < TELOPT_SUPDUP) 9036293Sroot printf("%s %s", fmt, telopts[option]); 9046024Ssam else 9056293Sroot printf("%s %d", fmt, option); 9066293Sroot if (*direction == '<') { 9076293Sroot printf("\r\n"); 9086293Sroot return; 9096293Sroot } 9106293Sroot printf(" (%s)\r\n", what ? "reply" : "don't reply"); 9116024Ssam } 912