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*26814Skarels static char sccsid[] = "@(#)telnet.c 5.5 (Berkeley) 03/11/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; 398378Ssam char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; 406000Sroot 416000Sroot char hisopts[256]; 426000Sroot char myopts[256]; 436000Sroot 446000Sroot char doopt[] = { IAC, DO, '%', 'c', 0 }; 456000Sroot char dont[] = { IAC, DONT, '%', 'c', 0 }; 466000Sroot char will[] = { IAC, WILL, '%', 'c', 0 }; 476000Sroot char wont[] = { IAC, WONT, '%', 'c', 0 }; 486000Sroot 496000Sroot int connected; 506000Sroot int net; 519972Ssam int showoptions = 0; 527377Sfeldman int options; 5310339Ssam int debug = 0; 549972Ssam int crmod = 0; 5525289Skarels int telnetport = 1; 566000Sroot char *prompt; 579972Ssam char escape = CTRL(]); 586000Sroot 596000Sroot char line[200]; 606000Sroot int margc; 616000Sroot char *margv[20]; 626000Sroot 636000Sroot jmp_buf toplevel; 646000Sroot jmp_buf peerdied; 656000Sroot 666000Sroot extern int errno; 676000Sroot 686000Sroot int tn(), quit(), suspend(), bye(), help(); 696024Ssam int setescape(), status(), toggle(), setoptions(); 7017922Sralph int setcrmod(), setdebug(), sendesc(), ayt(), intp(); 716000Sroot 728378Ssam #define HELPINDENT (sizeof ("connect")) 736000Sroot 746000Sroot struct cmd { 7511758Ssam char *name; /* command name */ 7611758Ssam char *help; /* help string */ 7711758Ssam int (*handler)(); /* routine which executes command */ 786000Sroot }; 796000Sroot 8011758Ssam char openhelp[] = "connect to a site"; 8111758Ssam char closehelp[] = "close current connection"; 8211758Ssam char quithelp[] = "exit telnet"; 8311758Ssam char zhelp[] = "suspend telnet"; 8411758Ssam char debughelp[] = "toggle debugging"; 8511758Ssam char escapehelp[] = "set escape character"; 8611758Ssam char statushelp[] = "print status information"; 8711758Ssam char helphelp[] = "print help information"; 8811758Ssam char optionshelp[] = "toggle viewing of options processing"; 8911758Ssam char crmodhelp[] = "toggle mapping of received carriage returns"; 9017922Sralph char sendeschelp[] = "send escape character"; 9125289Skarels char aythelp[] = "send \"Are You There\""; 9225289Skarels char intphelp[] = "send \"Interrupt Process\""; 936000Sroot 946000Sroot struct cmd cmdtab[] = { 9511758Ssam { "open", openhelp, tn }, 9611758Ssam { "close", closehelp, bye }, 9711758Ssam { "quit", quithelp, quit }, 986000Sroot { "z", zhelp, suspend }, 9911758Ssam { "escape", escapehelp, setescape }, 10011758Ssam { "status", statushelp, status }, 10111758Ssam { "options", optionshelp, setoptions }, 10211758Ssam { "crmod", crmodhelp, setcrmod }, 10311758Ssam { "debug", debughelp, setdebug }, 10417922Sralph { "ayt", aythelp, ayt }, 10517922Sralph { "interrupt", intphelp, intp }, 10617922Sralph { "passthru", sendeschelp, sendesc }, 10725289Skarels { "help", helphelp, help }, 10811758Ssam { "?", helphelp, help }, 1096000Sroot 0 1106000Sroot }; 1116000Sroot 1129972Ssam struct sockaddr_in sin; 1136000Sroot 1146000Sroot int intr(), deadpeer(); 1156000Sroot char *control(); 1166000Sroot struct cmd *getcmd(); 1178345Ssam struct servent *sp; 1186000Sroot 11913076Ssam struct tchars otc; 12013076Ssam struct ltchars oltc; 12113076Ssam struct sgttyb ottyb; 1228378Ssam 1236000Sroot main(argc, argv) 1246000Sroot int argc; 1256000Sroot char *argv[]; 1266000Sroot { 1278345Ssam sp = getservbyname("telnet", "tcp"); 1288345Ssam if (sp == 0) { 1298345Ssam fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 1308345Ssam exit(1); 1318345Ssam } 13213076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 13313076Ssam ioctl(0, TIOCGETC, (char *)&otc); 13413076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 1356000Sroot setbuf(stdin, 0); 1366000Sroot setbuf(stdout, 0); 1376000Sroot prompt = argv[0]; 13817484Sleres if (argc > 1 && !strcmp(argv[1], "-d")) { 13917484Sleres debug = 1; 14017484Sleres argv++; 14117484Sleres argc--; 14217484Sleres } 1436000Sroot if (argc != 1) { 1446000Sroot if (setjmp(toplevel) != 0) 1456000Sroot exit(0); 1466000Sroot tn(argc, argv); 1476000Sroot } 1486000Sroot setjmp(toplevel); 1496000Sroot for (;;) 1506000Sroot command(1); 1516000Sroot } 1526000Sroot 1538377Ssam char *hostname; 1548377Ssam char hnamebuf[32]; 1556000Sroot 1566000Sroot tn(argc, argv) 1576000Sroot int argc; 1586000Sroot char *argv[]; 1596000Sroot { 1606000Sroot register int c; 16125425Skarels register struct hostent *host = 0; 1626000Sroot 1636000Sroot if (connected) { 1648377Ssam printf("?Already connected to %s\n", hostname); 1656000Sroot return; 1666000Sroot } 1676000Sroot if (argc < 2) { 1686000Sroot strcpy(line, "Connect "); 1696000Sroot printf("(to) "); 1706000Sroot gets(&line[strlen(line)]); 1716000Sroot makeargv(); 1726000Sroot argc = margc; 1736000Sroot argv = margv; 1746000Sroot } 1756000Sroot if (argc > 3) { 1766000Sroot printf("usage: %s host-name [port]\n", argv[0]); 1776000Sroot return; 1786000Sroot } 17925425Skarels sin.sin_addr.s_addr = inet_addr(argv[1]); 18025425Skarels if (sin.sin_addr.s_addr != -1) { 18125425Skarels sin.sin_family = AF_INET; 18225425Skarels strcpy(hnamebuf, argv[1]); 18325425Skarels hostname = hnamebuf; 1848377Ssam } else { 18525425Skarels host = gethostbyname(argv[1]); 18625425Skarels if (host) { 18725425Skarels sin.sin_family = host->h_addrtype; 18825425Skarels bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 18925425Skarels host->h_length); 19025425Skarels hostname = host->h_name; 19125425Skarels } else { 1928377Ssam printf("%s: unknown host\n", argv[1]); 1938377Ssam return; 1948377Ssam } 1956000Sroot } 1968345Ssam sin.sin_port = sp->s_port; 1976024Ssam if (argc == 3) { 1986024Ssam sin.sin_port = atoi(argv[2]); 19925289Skarels if (sin.sin_port <= 0) { 20025289Skarels sp = getservbyname(argv[2], "tcp"); 20125289Skarels if (sp) 20225289Skarels sin.sin_port = sp->s_port; 20325289Skarels else { 20425289Skarels printf("%s: bad port number\n", argv[2]); 20525289Skarels return; 20625289Skarels } 20725289Skarels } else { 20825289Skarels sin.sin_port = atoi(argv[2]); 20925289Skarels sin.sin_port = htons(sin.sin_port); 2106024Ssam } 21125289Skarels telnetport = 0; 2126024Ssam } 21317922Sralph net = socket(AF_INET, SOCK_STREAM, 0); 2149217Ssam if (net < 0) { 2159217Ssam perror("telnet: socket"); 2166000Sroot return; 2176000Sroot } 21817484Sleres if (debug && 21917484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 22011758Ssam perror("setsockopt (SO_DEBUG)"); 22112989Ssam signal(SIGINT, intr); 22212989Ssam signal(SIGPIPE, deadpeer); 2236000Sroot printf("Trying...\n"); 22425425Skarels while (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) { 22525425Skarels if (host && host->h_addr_list[1]) { 22625425Skarels int oerrno = errno; 22725425Skarels 22825425Skarels fprintf(stderr, "telnet: connect to address %s: ", 22925425Skarels inet_ntoa(sin.sin_addr)); 23025425Skarels errno = oerrno; 23125425Skarels perror(0); 23225425Skarels host->h_addr_list++; 23325425Skarels bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 23425425Skarels host->h_length); 23525425Skarels fprintf(stderr, "Trying %s...\n", 23625425Skarels inet_ntoa(sin.sin_addr)); 237*26814Skarels (void) close(net); 238*26814Skarels net = socket(AF_INET, SOCK_STREAM, 0); 239*26814Skarels if (net < 0) { 240*26814Skarels perror("telnet: socket"); 241*26814Skarels return; 242*26814Skarels } 24325425Skarels continue; 24425425Skarels } 2459217Ssam perror("telnet: connect"); 24612989Ssam signal(SIGINT, SIG_DFL); 2476000Sroot return; 2486000Sroot } 2496000Sroot connected++; 2506000Sroot call(status, "status", 0); 2516000Sroot if (setjmp(peerdied) == 0) 2526000Sroot telnet(net); 2536000Sroot fprintf(stderr, "Connection closed by foreign host.\n"); 2546000Sroot exit(1); 2556000Sroot } 2566000Sroot 2576000Sroot /* 2586000Sroot * Print status about the connection. 2596000Sroot */ 2606000Sroot /*VARARGS*/ 2616000Sroot status() 2626000Sroot { 2636000Sroot if (connected) 2648377Ssam printf("Connected to %s.\n", hostname); 2656000Sroot else 2666000Sroot printf("No connection.\n"); 2676000Sroot printf("Escape character is '%s'.\n", control(escape)); 2689972Ssam fflush(stdout); 2696000Sroot } 2706000Sroot 2716000Sroot makeargv() 2726000Sroot { 2736000Sroot register char *cp; 2746000Sroot register char **argp = margv; 2756000Sroot 2766000Sroot margc = 0; 2776000Sroot for (cp = line; *cp;) { 2786000Sroot while (isspace(*cp)) 2796000Sroot cp++; 2806000Sroot if (*cp == '\0') 2816000Sroot break; 2826000Sroot *argp++ = cp; 2836000Sroot margc += 1; 2846000Sroot while (*cp != '\0' && !isspace(*cp)) 2856000Sroot cp++; 2866000Sroot if (*cp == '\0') 2876000Sroot break; 2886000Sroot *cp++ = '\0'; 2896000Sroot } 2906000Sroot *argp++ = 0; 2916000Sroot } 2926000Sroot 2936000Sroot /*VARARGS*/ 2946000Sroot suspend() 2956000Sroot { 2966000Sroot register int save; 2976000Sroot 2986000Sroot save = mode(0); 2998378Ssam kill(0, SIGTSTP); 3008378Ssam /* reget parameters in case they were changed */ 30113076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 30213076Ssam ioctl(0, TIOCGETC, (char *)&otc); 30313076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 3048378Ssam (void) mode(save); 3056000Sroot } 3066000Sroot 3076000Sroot /*VARARGS*/ 3086000Sroot bye() 3096000Sroot { 3108378Ssam register char *op; 3116000Sroot 3128378Ssam (void) mode(0); 3136000Sroot if (connected) { 31411758Ssam shutdown(net, 2); 3156000Sroot printf("Connection closed.\n"); 3166000Sroot close(net); 3176000Sroot connected = 0; 3188378Ssam /* reset his options */ 3198378Ssam for (op = hisopts; op < &hisopts[256]; op++) 3208378Ssam *op = 0; 3216000Sroot } 3226000Sroot } 3236000Sroot 3246000Sroot /*VARARGS*/ 3256000Sroot quit() 3266000Sroot { 3276000Sroot call(bye, "bye", 0); 3286000Sroot exit(0); 3296000Sroot } 3306000Sroot 3316000Sroot /* 3326000Sroot * Help command. 3336000Sroot */ 3346000Sroot help(argc, argv) 3356000Sroot int argc; 3366000Sroot char *argv[]; 3376000Sroot { 3386000Sroot register struct cmd *c; 3396000Sroot 3406000Sroot if (argc == 1) { 3416000Sroot printf("Commands may be abbreviated. Commands are:\n\n"); 3426000Sroot for (c = cmdtab; c->name; c++) 3436000Sroot printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 3446000Sroot return; 3456000Sroot } 3466000Sroot while (--argc > 0) { 3476000Sroot register char *arg; 3486000Sroot arg = *++argv; 3496000Sroot c = getcmd(arg); 3506000Sroot if (c == (struct cmd *)-1) 3516000Sroot printf("?Ambiguous help command %s\n", arg); 3526000Sroot else if (c == (struct cmd *)0) 3536000Sroot printf("?Invalid help command %s\n", arg); 3546000Sroot else 3556000Sroot printf("%s\n", c->help); 3566000Sroot } 3576000Sroot } 3586000Sroot 3596000Sroot /* 3606000Sroot * Call routine with argc, argv set from args (terminated by 0). 3616000Sroot * VARARGS2 3626000Sroot */ 3636000Sroot call(routine, args) 3646000Sroot int (*routine)(); 3656000Sroot int args; 3666000Sroot { 3676000Sroot register int *argp; 3686000Sroot register int argc; 3696000Sroot 3706000Sroot for (argc = 0, argp = &args; *argp++ != 0; argc++) 3716000Sroot ; 3726000Sroot (*routine)(argc, &args); 3736000Sroot } 3746000Sroot 37513076Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 37613076Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3779972Ssam 3786000Sroot mode(f) 3796000Sroot register int f; 3806000Sroot { 3818378Ssam static int prevmode = 0; 38213076Ssam struct tchars *tc; 38313076Ssam struct ltchars *ltc; 38413076Ssam struct sgttyb sb; 38513076Ssam int onoff, old; 3866000Sroot 3878378Ssam if (prevmode == f) 3888378Ssam return (f); 3898378Ssam old = prevmode; 3908378Ssam prevmode = f; 39113076Ssam sb = ottyb; 3926000Sroot switch (f) { 3938378Ssam 3946000Sroot case 0: 3956000Sroot onoff = 0; 3969972Ssam tc = &otc; 39713076Ssam ltc = &oltc; 3986000Sroot break; 3996000Sroot 4006000Sroot case 1: 4016000Sroot case 2: 40213076Ssam sb.sg_flags |= CBREAK; 4038378Ssam if (f == 1) 40413076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 4058378Ssam else 40613076Ssam sb.sg_flags |= ECHO|CRMOD; 40713076Ssam sb.sg_erase = sb.sg_kill = -1; 4089972Ssam tc = ¬c; 40913076Ssam ltc = &noltc; 4106000Sroot onoff = 1; 4119972Ssam break; 4129972Ssam 4139972Ssam default: 4149972Ssam return; 4156000Sroot } 41613076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 41713076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 41813076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 4196000Sroot ioctl(fileno(stdin), FIONBIO, &onoff); 4206000Sroot ioctl(fileno(stdout), FIONBIO, &onoff); 4216000Sroot return (old); 4226000Sroot } 4236000Sroot 4246000Sroot char sibuf[BUFSIZ], *sbp; 4256000Sroot char tibuf[BUFSIZ], *tbp; 4266000Sroot int scc, tcc; 4276000Sroot 4286000Sroot /* 4296000Sroot * Select from tty and network... 4306000Sroot */ 4316000Sroot telnet(s) 4326000Sroot int s; 4336000Sroot { 4346000Sroot register int c; 4356000Sroot int tin = fileno(stdin), tout = fileno(stdout); 4366000Sroot int on = 1; 4376000Sroot 4388378Ssam (void) mode(2); 4396000Sroot ioctl(s, FIONBIO, &on); 44025289Skarels if (telnetport && !hisopts[TELOPT_SGA]) 44117922Sralph willoption(TELOPT_SGA); 4426000Sroot for (;;) { 4436000Sroot int ibits = 0, obits = 0; 4446000Sroot 4456000Sroot if (nfrontp - nbackp) 4466000Sroot obits |= (1 << s); 4476000Sroot else 4486000Sroot ibits |= (1 << tin); 4496000Sroot if (tfrontp - tbackp) 4506000Sroot obits |= (1 << tout); 4516000Sroot else 4526000Sroot ibits |= (1 << s); 4536000Sroot if (scc < 0 && tcc < 0) 4546000Sroot break; 4559217Ssam select(16, &ibits, &obits, 0, 0); 4566000Sroot if (ibits == 0 && obits == 0) { 4576000Sroot sleep(5); 4586000Sroot continue; 4596000Sroot } 4606000Sroot 4616000Sroot /* 4626000Sroot * Something to read from the network... 4636000Sroot */ 4646000Sroot if (ibits & (1 << s)) { 4658378Ssam scc = read(s, sibuf, sizeof (sibuf)); 4666000Sroot if (scc < 0 && errno == EWOULDBLOCK) 4676000Sroot scc = 0; 4686000Sroot else { 4696000Sroot if (scc <= 0) 4706000Sroot break; 4716000Sroot sbp = sibuf; 4726000Sroot } 4736000Sroot } 4746000Sroot 4756000Sroot /* 4766000Sroot * Something to read from the tty... 4776000Sroot */ 4786000Sroot if (ibits & (1 << tin)) { 4798378Ssam tcc = read(tin, tibuf, sizeof (tibuf)); 4806000Sroot if (tcc < 0 && errno == EWOULDBLOCK) 4816000Sroot tcc = 0; 4826000Sroot else { 4836000Sroot if (tcc <= 0) 4846000Sroot break; 4856000Sroot tbp = tibuf; 4866000Sroot } 4876000Sroot } 4886000Sroot 4896000Sroot while (tcc > 0) { 4906000Sroot register int c; 4916000Sroot 4926000Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 4936000Sroot break; 4946000Sroot c = *tbp++ & 0377, tcc--; 4956000Sroot if (strip(c) == escape) { 4966000Sroot command(0); 4976000Sroot tcc = 0; 4986000Sroot break; 4996000Sroot } 50017922Sralph switch (c) { 50117922Sralph case '\n': 50217922Sralph if (!hisopts[TELOPT_ECHO]) 50317922Sralph *nfrontp++ = '\r'; 50417922Sralph *nfrontp++ = '\n'; 50517922Sralph break; 50617922Sralph case '\r': 50717922Sralph *nfrontp++ = '\r'; 50817922Sralph if (hisopts[TELOPT_ECHO]) 50917922Sralph *nfrontp++ = '\n'; 51017922Sralph else 51117922Sralph *nfrontp++ = '\0'; 51217922Sralph break; 51317922Sralph case IAC: 51417922Sralph *nfrontp++ = IAC; 51517922Sralph /* fall into ... */ 51617922Sralph default: 51711758Ssam *nfrontp++ = c; 51817922Sralph break; 51917922Sralph } 5206000Sroot } 5216000Sroot if ((obits & (1 << s)) && (nfrontp - nbackp) > 0) 5226000Sroot netflush(s); 5236000Sroot if (scc > 0) 5246000Sroot telrcv(); 5256000Sroot if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0) 5266000Sroot ttyflush(tout); 5276000Sroot } 5288378Ssam (void) mode(0); 5296000Sroot } 5306000Sroot 5316000Sroot command(top) 5326000Sroot int top; 5336000Sroot { 5346000Sroot register struct cmd *c; 5356000Sroot int oldmode, wasopen; 5366000Sroot 5376000Sroot oldmode = mode(0); 5386000Sroot if (!top) 5396000Sroot putchar('\n'); 5406000Sroot else 54112989Ssam signal(SIGINT, SIG_DFL); 5426000Sroot for (;;) { 5436000Sroot printf("%s> ", prompt); 54413997Ssam if (gets(line) == 0) { 54525800Slepreau if (feof(stdin)) 54625800Slepreau quit(); 5476000Sroot break; 54813997Ssam } 5496000Sroot if (line[0] == 0) 5506000Sroot break; 5516000Sroot makeargv(); 5526000Sroot c = getcmd(margv[0]); 5536000Sroot if (c == (struct cmd *)-1) { 5546000Sroot printf("?Ambiguous command\n"); 5556000Sroot continue; 5566000Sroot } 5576000Sroot if (c == 0) { 5586000Sroot printf("?Invalid command\n"); 5596000Sroot continue; 5606000Sroot } 5616000Sroot (*c->handler)(margc, margv); 5626000Sroot if (c->handler != help) 5636000Sroot break; 5646000Sroot } 5656000Sroot if (!top) { 5666000Sroot if (!connected) 5676000Sroot longjmp(toplevel, 1); 5688378Ssam (void) mode(oldmode); 5696000Sroot } 5706000Sroot } 5716000Sroot 5726000Sroot /* 5736000Sroot * Telnet receiver states for fsm 5746000Sroot */ 5756000Sroot #define TS_DATA 0 5766000Sroot #define TS_IAC 1 5776000Sroot #define TS_WILL 2 5786000Sroot #define TS_WONT 3 5796000Sroot #define TS_DO 4 5806000Sroot #define TS_DONT 5 5816000Sroot 5826000Sroot telrcv() 5836000Sroot { 5846000Sroot register int c; 5856000Sroot static int state = TS_DATA; 5866000Sroot 5876000Sroot while (scc > 0) { 5886000Sroot c = *sbp++ & 0377, scc--; 5896000Sroot switch (state) { 5906000Sroot 5916000Sroot case TS_DATA: 5929972Ssam if (c == IAC) { 5936000Sroot state = TS_IAC; 5949972Ssam continue; 5959972Ssam } 5969972Ssam *tfrontp++ = c; 5979972Ssam /* 5989972Ssam * This hack is needed since we can't set 5999972Ssam * CRMOD on output only. Machines like MULTICS 6009972Ssam * like to send \r without \n; since we must 6019972Ssam * turn off CRMOD to get proper input, the mapping 6029972Ssam * is done here (sigh). 6039972Ssam */ 6049972Ssam if (c == '\r' && crmod) 6059972Ssam *tfrontp++ = '\n'; 6066000Sroot continue; 6076000Sroot 6086000Sroot case TS_IAC: 6096000Sroot switch (c) { 6106000Sroot 6116000Sroot case WILL: 6126000Sroot state = TS_WILL; 6136000Sroot continue; 6146000Sroot 6156000Sroot case WONT: 6166000Sroot state = TS_WONT; 6176000Sroot continue; 6186000Sroot 6196000Sroot case DO: 6206000Sroot state = TS_DO; 6216000Sroot continue; 6226000Sroot 6236000Sroot case DONT: 6246000Sroot state = TS_DONT; 6256000Sroot continue; 6266000Sroot 6276000Sroot case DM: 6286000Sroot ioctl(fileno(stdout), TIOCFLUSH, 0); 6296000Sroot break; 6306000Sroot 6316000Sroot case NOP: 6326000Sroot case GA: 6336000Sroot break; 6346000Sroot 6356000Sroot default: 6366000Sroot break; 6376000Sroot } 6386000Sroot state = TS_DATA; 6396000Sroot continue; 6406000Sroot 6416000Sroot case TS_WILL: 6428345Ssam printoption("RCVD", will, c, !hisopts[c]); 6436000Sroot if (!hisopts[c]) 6446000Sroot willoption(c); 6456000Sroot state = TS_DATA; 6466000Sroot continue; 6476000Sroot 6486000Sroot case TS_WONT: 6498345Ssam printoption("RCVD", wont, c, hisopts[c]); 6506000Sroot if (hisopts[c]) 6516000Sroot wontoption(c); 6526000Sroot state = TS_DATA; 6536000Sroot continue; 6546000Sroot 6556000Sroot case TS_DO: 6568345Ssam printoption("RCVD", doopt, c, !myopts[c]); 6576000Sroot if (!myopts[c]) 6586000Sroot dooption(c); 6596000Sroot state = TS_DATA; 6606000Sroot continue; 6616000Sroot 6626000Sroot case TS_DONT: 6638345Ssam printoption("RCVD", dont, c, myopts[c]); 6646000Sroot if (myopts[c]) { 6656000Sroot myopts[c] = 0; 6666000Sroot sprintf(nfrontp, wont, c); 6678378Ssam nfrontp += sizeof (wont) - 2; 6688345Ssam printoption("SENT", wont, c); 6696000Sroot } 6706000Sroot state = TS_DATA; 6716000Sroot continue; 6726000Sroot } 6736000Sroot } 6746000Sroot } 6756000Sroot 6766000Sroot willoption(option) 6776000Sroot int option; 6786000Sroot { 6796000Sroot char *fmt; 6806000Sroot 6816000Sroot switch (option) { 6826000Sroot 6836000Sroot case TELOPT_ECHO: 6848378Ssam (void) mode(1); 6856000Sroot 6866000Sroot case TELOPT_SGA: 6876000Sroot hisopts[option] = 1; 6886000Sroot fmt = doopt; 6896000Sroot break; 6906000Sroot 6916000Sroot case TELOPT_TM: 6926000Sroot fmt = dont; 6936000Sroot break; 6946000Sroot 6956000Sroot default: 6966000Sroot fmt = dont; 6976000Sroot break; 6986000Sroot } 6996024Ssam sprintf(nfrontp, fmt, option); 7008378Ssam nfrontp += sizeof (dont) - 2; 7018345Ssam printoption("SENT", fmt, option); 7026000Sroot } 7036000Sroot 7046000Sroot wontoption(option) 7056000Sroot int option; 7066000Sroot { 7076000Sroot char *fmt; 7086000Sroot 7096000Sroot switch (option) { 7106000Sroot 7116000Sroot case TELOPT_ECHO: 7128378Ssam (void) mode(2); 7136000Sroot 7146000Sroot case TELOPT_SGA: 7156000Sroot hisopts[option] = 0; 7166000Sroot fmt = dont; 7176000Sroot break; 7186000Sroot 7196000Sroot default: 7206000Sroot fmt = dont; 7216000Sroot } 7226000Sroot sprintf(nfrontp, fmt, option); 7238378Ssam nfrontp += sizeof (doopt) - 2; 7248345Ssam printoption("SENT", fmt, option); 7256000Sroot } 7266000Sroot 7276000Sroot dooption(option) 7286000Sroot int option; 7296000Sroot { 7306000Sroot char *fmt; 7316000Sroot 7326000Sroot switch (option) { 7336000Sroot 7346000Sroot case TELOPT_TM: 7356000Sroot fmt = wont; 7366000Sroot break; 7376000Sroot 73813231Ssam case TELOPT_ECHO: 73913231Ssam (void) mode(2); 74013231Ssam fmt = will; 74113231Ssam hisopts[option] = 0; 74213231Ssam break; 74313231Ssam 7446000Sroot case TELOPT_SGA: 7456000Sroot fmt = will; 7466000Sroot break; 7476000Sroot 7486000Sroot default: 7496000Sroot fmt = wont; 7506000Sroot break; 7516000Sroot } 7526000Sroot sprintf(nfrontp, fmt, option); 7538378Ssam nfrontp += sizeof (doopt) - 2; 7548345Ssam printoption("SENT", fmt, option); 7556000Sroot } 7566000Sroot 7576000Sroot /* 7586000Sroot * Set the escape character. 7596000Sroot */ 7606000Sroot setescape(argc, argv) 7616000Sroot int argc; 7626000Sroot char *argv[]; 7636000Sroot { 7646000Sroot register char *arg; 7656000Sroot char buf[50]; 7666000Sroot 7676000Sroot if (argc > 2) 7686000Sroot arg = argv[1]; 7696000Sroot else { 7706000Sroot printf("new escape character: "); 7716000Sroot gets(buf); 7726000Sroot arg = buf; 7736000Sroot } 7746000Sroot if (arg[0] != '\0') 7756000Sroot escape = arg[0]; 7766000Sroot printf("Escape character is '%s'.\n", control(escape)); 7779972Ssam fflush(stdout); 7786000Sroot } 7796000Sroot 7806024Ssam /*VARARGS*/ 7816024Ssam setoptions() 7826024Ssam { 7839972Ssam 7846024Ssam showoptions = !showoptions; 78525289Skarels printf("%s show option processing.\n", showoptions ? "Will" : "Won't"); 7869972Ssam fflush(stdout); 7876024Ssam } 7886024Ssam 7899972Ssam /*VARARGS*/ 7909972Ssam setcrmod() 7919972Ssam { 7929972Ssam 7939972Ssam crmod = !crmod; 79425289Skarels printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 7959972Ssam fflush(stdout); 7969972Ssam } 7979972Ssam 79810339Ssam /*VARARGS*/ 79910339Ssam setdebug() 80010339Ssam { 80110339Ssam 80217484Sleres debug = debug ? 0 : 1; 80310339Ssam printf("%s turn on socket level debugging.\n", 80425289Skarels debug ? "Will" : "Won't"); 80510339Ssam fflush(stdout); 80617484Sleres if (net > 0 && 80717484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 80811758Ssam perror("setsockopt (SO_DEBUG)"); 80910339Ssam } 81010339Ssam 81117922Sralph sendesc() 81217922Sralph { 81317922Sralph *nfrontp++ = escape; 81417922Sralph } 81517922Sralph 81617922Sralph ayt() 81717922Sralph { 81817922Sralph *nfrontp++ = IAC; 81917922Sralph *nfrontp++ = AYT; 82017922Sralph } 82117922Sralph 82217922Sralph intp() 82317922Sralph { 82417922Sralph *nfrontp++ = IAC; 82517922Sralph *nfrontp++ = IP; 82617922Sralph } 82717922Sralph 8286000Sroot /* 8296000Sroot * Construct a control character sequence 8306000Sroot * for a special character. 8316000Sroot */ 8326000Sroot char * 8336000Sroot control(c) 8346000Sroot register int c; 8356000Sroot { 8366000Sroot static char buf[3]; 8376000Sroot 8386000Sroot if (c == 0177) 8396000Sroot return ("^?"); 8406000Sroot if (c >= 040) { 8416000Sroot buf[0] = c; 8426000Sroot buf[1] = 0; 8436000Sroot } else { 8446000Sroot buf[0] = '^'; 8456000Sroot buf[1] = '@'+c; 8466000Sroot buf[2] = 0; 8476000Sroot } 8486000Sroot return (buf); 8496000Sroot } 8506000Sroot 8516000Sroot struct cmd * 8526000Sroot getcmd(name) 8536000Sroot register char *name; 8546000Sroot { 8556000Sroot register char *p, *q; 8566000Sroot register struct cmd *c, *found; 8576000Sroot register int nmatches, longest; 8586000Sroot 8596000Sroot longest = 0; 8606000Sroot nmatches = 0; 8616000Sroot found = 0; 8626000Sroot for (c = cmdtab; p = c->name; c++) { 8636000Sroot for (q = name; *q == *p++; q++) 8646000Sroot if (*q == 0) /* exact match? */ 8656000Sroot return (c); 8666000Sroot if (!*q) { /* the name was a prefix */ 8676000Sroot if (q - name > longest) { 8686000Sroot longest = q - name; 8696000Sroot nmatches = 1; 8706000Sroot found = c; 8716000Sroot } else if (q - name == longest) 8726000Sroot nmatches++; 8736000Sroot } 8746000Sroot } 8756000Sroot if (nmatches > 1) 8766000Sroot return ((struct cmd *)-1); 8776000Sroot return (found); 8786000Sroot } 8796000Sroot 8806000Sroot deadpeer() 8816000Sroot { 8828378Ssam (void) mode(0); 8836000Sroot longjmp(peerdied, -1); 8846000Sroot } 8856000Sroot 8866000Sroot intr() 8876000Sroot { 8888378Ssam (void) mode(0); 8896000Sroot longjmp(toplevel, -1); 8906000Sroot } 8916000Sroot 8926000Sroot ttyflush(fd) 8936000Sroot { 8946000Sroot int n; 8956000Sroot 8966000Sroot if ((n = tfrontp - tbackp) > 0) 8976000Sroot n = write(fd, tbackp, n); 8988345Ssam if (n < 0) 8998345Ssam return; 9006000Sroot tbackp += n; 9016000Sroot if (tbackp == tfrontp) 9026000Sroot tbackp = tfrontp = ttyobuf; 9036000Sroot } 9046000Sroot 9056000Sroot netflush(fd) 9066000Sroot { 9076000Sroot int n; 9086000Sroot 9096000Sroot if ((n = nfrontp - nbackp) > 0) 9106000Sroot n = write(fd, nbackp, n); 9116501Ssam if (n < 0) { 9126501Ssam if (errno != ENOBUFS && errno != EWOULDBLOCK) { 9138378Ssam (void) mode(0); 9148377Ssam perror(hostname); 9156501Ssam close(fd); 9166501Ssam longjmp(peerdied, -1); 9176501Ssam /*NOTREACHED*/ 9186501Ssam } 9196000Sroot n = 0; 9206501Ssam } 9216000Sroot nbackp += n; 9226000Sroot if (nbackp == nfrontp) 9236000Sroot nbackp = nfrontp = netobuf; 9246000Sroot } 9256024Ssam 9266293Sroot /*VARARGS*/ 9276293Sroot printoption(direction, fmt, option, what) 9286024Ssam char *direction, *fmt; 9296293Sroot int option, what; 9306024Ssam { 9318345Ssam if (!showoptions) 9328345Ssam return; 9336024Ssam printf("%s ", direction); 9346024Ssam if (fmt == doopt) 9356024Ssam fmt = "do"; 9366024Ssam else if (fmt == dont) 9376024Ssam fmt = "dont"; 9386024Ssam else if (fmt == will) 9396024Ssam fmt = "will"; 9406024Ssam else if (fmt == wont) 9416024Ssam fmt = "wont"; 9426024Ssam else 9436024Ssam fmt = "???"; 9446024Ssam if (option < TELOPT_SUPDUP) 9456293Sroot printf("%s %s", fmt, telopts[option]); 9466024Ssam else 9476293Sroot printf("%s %d", fmt, option); 9486293Sroot if (*direction == '<') { 9496293Sroot printf("\r\n"); 9506293Sroot return; 9516293Sroot } 9526293Sroot printf(" (%s)\r\n", what ? "reply" : "don't reply"); 9536024Ssam } 954