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*25289Skarels static char sccsid[] = "@(#)telnet.c 5.2 (Berkeley) 10/24/85"; 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; 55*25289Skarels 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"; 91*25289Skarels char aythelp[] = "send \"Are You There\""; 92*25289Skarels 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 }, 107*25289Skarels { "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; 1618377Ssam register struct hostent *host; 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 } 1798345Ssam host = gethostbyname(argv[1]); 1808377Ssam if (host) { 1819217Ssam sin.sin_family = host->h_addrtype; 1829217Ssam bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length); 1838377Ssam hostname = host->h_name; 1848377Ssam } else { 1859217Ssam sin.sin_family = AF_INET; 1868377Ssam sin.sin_addr.s_addr = inet_addr(argv[1]); 1878377Ssam if (sin.sin_addr.s_addr == -1) { 1888377Ssam printf("%s: unknown host\n", argv[1]); 1898377Ssam return; 1908377Ssam } 1918377Ssam strcpy(hnamebuf, argv[1]); 1928377Ssam hostname = hnamebuf; 1936000Sroot } 1948345Ssam sin.sin_port = sp->s_port; 1956024Ssam if (argc == 3) { 1966024Ssam sin.sin_port = atoi(argv[2]); 197*25289Skarels if (sin.sin_port <= 0) { 198*25289Skarels sp = getservbyname(argv[2], "tcp"); 199*25289Skarels if (sp) 200*25289Skarels sin.sin_port = sp->s_port; 201*25289Skarels else { 202*25289Skarels printf("%s: bad port number\n", argv[2]); 203*25289Skarels return; 204*25289Skarels } 205*25289Skarels } else { 206*25289Skarels sin.sin_port = atoi(argv[2]); 207*25289Skarels sin.sin_port = htons(sin.sin_port); 2086024Ssam } 209*25289Skarels telnetport = 0; 2106024Ssam } 21117922Sralph net = socket(AF_INET, SOCK_STREAM, 0); 2129217Ssam if (net < 0) { 2139217Ssam perror("telnet: socket"); 2146000Sroot return; 2156000Sroot } 21617484Sleres if (debug && 21717484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 21811758Ssam perror("setsockopt (SO_DEBUG)"); 21912989Ssam signal(SIGINT, intr); 22012989Ssam signal(SIGPIPE, deadpeer); 2216000Sroot printf("Trying...\n"); 22217922Sralph if (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) { 2239217Ssam perror("telnet: connect"); 22412989Ssam signal(SIGINT, SIG_DFL); 2256000Sroot return; 2266000Sroot } 2276000Sroot connected++; 2286000Sroot call(status, "status", 0); 2296000Sroot if (setjmp(peerdied) == 0) 2306000Sroot telnet(net); 2316000Sroot fprintf(stderr, "Connection closed by foreign host.\n"); 2326000Sroot exit(1); 2336000Sroot } 2346000Sroot 2356000Sroot /* 2366000Sroot * Print status about the connection. 2376000Sroot */ 2386000Sroot /*VARARGS*/ 2396000Sroot status() 2406000Sroot { 2416000Sroot if (connected) 2428377Ssam printf("Connected to %s.\n", hostname); 2436000Sroot else 2446000Sroot printf("No connection.\n"); 2456000Sroot printf("Escape character is '%s'.\n", control(escape)); 2469972Ssam fflush(stdout); 2476000Sroot } 2486000Sroot 2496000Sroot makeargv() 2506000Sroot { 2516000Sroot register char *cp; 2526000Sroot register char **argp = margv; 2536000Sroot 2546000Sroot margc = 0; 2556000Sroot for (cp = line; *cp;) { 2566000Sroot while (isspace(*cp)) 2576000Sroot cp++; 2586000Sroot if (*cp == '\0') 2596000Sroot break; 2606000Sroot *argp++ = cp; 2616000Sroot margc += 1; 2626000Sroot while (*cp != '\0' && !isspace(*cp)) 2636000Sroot cp++; 2646000Sroot if (*cp == '\0') 2656000Sroot break; 2666000Sroot *cp++ = '\0'; 2676000Sroot } 2686000Sroot *argp++ = 0; 2696000Sroot } 2706000Sroot 2716000Sroot /*VARARGS*/ 2726000Sroot suspend() 2736000Sroot { 2746000Sroot register int save; 2756000Sroot 2766000Sroot save = mode(0); 2778378Ssam kill(0, SIGTSTP); 2788378Ssam /* reget parameters in case they were changed */ 27913076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 28013076Ssam ioctl(0, TIOCGETC, (char *)&otc); 28113076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 2828378Ssam (void) mode(save); 2836000Sroot } 2846000Sroot 2856000Sroot /*VARARGS*/ 2866000Sroot bye() 2876000Sroot { 2888378Ssam register char *op; 2896000Sroot 2908378Ssam (void) mode(0); 2916000Sroot if (connected) { 29211758Ssam shutdown(net, 2); 2936000Sroot printf("Connection closed.\n"); 2946000Sroot close(net); 2956000Sroot connected = 0; 2968378Ssam /* reset his options */ 2978378Ssam for (op = hisopts; op < &hisopts[256]; op++) 2988378Ssam *op = 0; 2996000Sroot } 3006000Sroot } 3016000Sroot 3026000Sroot /*VARARGS*/ 3036000Sroot quit() 3046000Sroot { 3056000Sroot call(bye, "bye", 0); 3066000Sroot exit(0); 3076000Sroot } 3086000Sroot 3096000Sroot /* 3106000Sroot * Help command. 3116000Sroot */ 3126000Sroot help(argc, argv) 3136000Sroot int argc; 3146000Sroot char *argv[]; 3156000Sroot { 3166000Sroot register struct cmd *c; 3176000Sroot 3186000Sroot if (argc == 1) { 3196000Sroot printf("Commands may be abbreviated. Commands are:\n\n"); 3206000Sroot for (c = cmdtab; c->name; c++) 3216000Sroot printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 3226000Sroot return; 3236000Sroot } 3246000Sroot while (--argc > 0) { 3256000Sroot register char *arg; 3266000Sroot arg = *++argv; 3276000Sroot c = getcmd(arg); 3286000Sroot if (c == (struct cmd *)-1) 3296000Sroot printf("?Ambiguous help command %s\n", arg); 3306000Sroot else if (c == (struct cmd *)0) 3316000Sroot printf("?Invalid help command %s\n", arg); 3326000Sroot else 3336000Sroot printf("%s\n", c->help); 3346000Sroot } 3356000Sroot } 3366000Sroot 3376000Sroot /* 3386000Sroot * Call routine with argc, argv set from args (terminated by 0). 3396000Sroot * VARARGS2 3406000Sroot */ 3416000Sroot call(routine, args) 3426000Sroot int (*routine)(); 3436000Sroot int args; 3446000Sroot { 3456000Sroot register int *argp; 3466000Sroot register int argc; 3476000Sroot 3486000Sroot for (argc = 0, argp = &args; *argp++ != 0; argc++) 3496000Sroot ; 3506000Sroot (*routine)(argc, &args); 3516000Sroot } 3526000Sroot 35313076Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 35413076Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3559972Ssam 3566000Sroot mode(f) 3576000Sroot register int f; 3586000Sroot { 3598378Ssam static int prevmode = 0; 36013076Ssam struct tchars *tc; 36113076Ssam struct ltchars *ltc; 36213076Ssam struct sgttyb sb; 36313076Ssam int onoff, old; 3646000Sroot 3658378Ssam if (prevmode == f) 3668378Ssam return (f); 3678378Ssam old = prevmode; 3688378Ssam prevmode = f; 36913076Ssam sb = ottyb; 3706000Sroot switch (f) { 3718378Ssam 3726000Sroot case 0: 3736000Sroot onoff = 0; 3749972Ssam tc = &otc; 37513076Ssam ltc = &oltc; 3766000Sroot break; 3776000Sroot 3786000Sroot case 1: 3796000Sroot case 2: 38013076Ssam sb.sg_flags |= CBREAK; 3818378Ssam if (f == 1) 38213076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 3838378Ssam else 38413076Ssam sb.sg_flags |= ECHO|CRMOD; 38513076Ssam sb.sg_erase = sb.sg_kill = -1; 3869972Ssam tc = ¬c; 38713076Ssam ltc = &noltc; 3886000Sroot onoff = 1; 3899972Ssam break; 3909972Ssam 3919972Ssam default: 3929972Ssam return; 3936000Sroot } 39413076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 39513076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 39613076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 3976000Sroot ioctl(fileno(stdin), FIONBIO, &onoff); 3986000Sroot ioctl(fileno(stdout), FIONBIO, &onoff); 3996000Sroot return (old); 4006000Sroot } 4016000Sroot 4026000Sroot char sibuf[BUFSIZ], *sbp; 4036000Sroot char tibuf[BUFSIZ], *tbp; 4046000Sroot int scc, tcc; 4056000Sroot 4066000Sroot /* 4076000Sroot * Select from tty and network... 4086000Sroot */ 4096000Sroot telnet(s) 4106000Sroot int s; 4116000Sroot { 4126000Sroot register int c; 4136000Sroot int tin = fileno(stdin), tout = fileno(stdout); 4146000Sroot int on = 1; 4156000Sroot 4168378Ssam (void) mode(2); 4176000Sroot ioctl(s, FIONBIO, &on); 418*25289Skarels if (telnetport && !hisopts[TELOPT_SGA]) 41917922Sralph willoption(TELOPT_SGA); 4206000Sroot for (;;) { 4216000Sroot int ibits = 0, obits = 0; 4226000Sroot 4236000Sroot if (nfrontp - nbackp) 4246000Sroot obits |= (1 << s); 4256000Sroot else 4266000Sroot ibits |= (1 << tin); 4276000Sroot if (tfrontp - tbackp) 4286000Sroot obits |= (1 << tout); 4296000Sroot else 4306000Sroot ibits |= (1 << s); 4316000Sroot if (scc < 0 && tcc < 0) 4326000Sroot break; 4339217Ssam select(16, &ibits, &obits, 0, 0); 4346000Sroot if (ibits == 0 && obits == 0) { 4356000Sroot sleep(5); 4366000Sroot continue; 4376000Sroot } 4386000Sroot 4396000Sroot /* 4406000Sroot * Something to read from the network... 4416000Sroot */ 4426000Sroot if (ibits & (1 << s)) { 4438378Ssam scc = read(s, sibuf, sizeof (sibuf)); 4446000Sroot if (scc < 0 && errno == EWOULDBLOCK) 4456000Sroot scc = 0; 4466000Sroot else { 4476000Sroot if (scc <= 0) 4486000Sroot break; 4496000Sroot sbp = sibuf; 4506000Sroot } 4516000Sroot } 4526000Sroot 4536000Sroot /* 4546000Sroot * Something to read from the tty... 4556000Sroot */ 4566000Sroot if (ibits & (1 << tin)) { 4578378Ssam tcc = read(tin, tibuf, sizeof (tibuf)); 4586000Sroot if (tcc < 0 && errno == EWOULDBLOCK) 4596000Sroot tcc = 0; 4606000Sroot else { 4616000Sroot if (tcc <= 0) 4626000Sroot break; 4636000Sroot tbp = tibuf; 4646000Sroot } 4656000Sroot } 4666000Sroot 4676000Sroot while (tcc > 0) { 4686000Sroot register int c; 4696000Sroot 4706000Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 4716000Sroot break; 4726000Sroot c = *tbp++ & 0377, tcc--; 4736000Sroot if (strip(c) == escape) { 4746000Sroot command(0); 4756000Sroot tcc = 0; 4766000Sroot break; 4776000Sroot } 47817922Sralph switch (c) { 47917922Sralph case '\n': 48017922Sralph if (!hisopts[TELOPT_ECHO]) 48117922Sralph *nfrontp++ = '\r'; 48217922Sralph *nfrontp++ = '\n'; 48317922Sralph break; 48417922Sralph case '\r': 48517922Sralph *nfrontp++ = '\r'; 48617922Sralph if (hisopts[TELOPT_ECHO]) 48717922Sralph *nfrontp++ = '\n'; 48817922Sralph else 48917922Sralph *nfrontp++ = '\0'; 49017922Sralph break; 49117922Sralph case IAC: 49217922Sralph *nfrontp++ = IAC; 49317922Sralph /* fall into ... */ 49417922Sralph default: 49511758Ssam *nfrontp++ = c; 49617922Sralph break; 49717922Sralph } 4986000Sroot } 4996000Sroot if ((obits & (1 << s)) && (nfrontp - nbackp) > 0) 5006000Sroot netflush(s); 5016000Sroot if (scc > 0) 5026000Sroot telrcv(); 5036000Sroot if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0) 5046000Sroot ttyflush(tout); 5056000Sroot } 5068378Ssam (void) mode(0); 5076000Sroot } 5086000Sroot 5096000Sroot command(top) 5106000Sroot int top; 5116000Sroot { 5126000Sroot register struct cmd *c; 5136000Sroot int oldmode, wasopen; 5146000Sroot 5156000Sroot oldmode = mode(0); 5166000Sroot if (!top) 5176000Sroot putchar('\n'); 5186000Sroot else 51912989Ssam signal(SIGINT, SIG_DFL); 5206000Sroot for (;;) { 5216000Sroot printf("%s> ", prompt); 52213997Ssam if (gets(line) == 0) { 52313997Ssam if (feof(stdin)) { 52413997Ssam clearerr(stdin); 52513997Ssam putchar('\n'); 52613997Ssam } 5276000Sroot break; 52813997Ssam } 5296000Sroot if (line[0] == 0) 5306000Sroot break; 5316000Sroot makeargv(); 5326000Sroot c = getcmd(margv[0]); 5336000Sroot if (c == (struct cmd *)-1) { 5346000Sroot printf("?Ambiguous command\n"); 5356000Sroot continue; 5366000Sroot } 5376000Sroot if (c == 0) { 5386000Sroot printf("?Invalid command\n"); 5396000Sroot continue; 5406000Sroot } 5416000Sroot (*c->handler)(margc, margv); 5426000Sroot if (c->handler != help) 5436000Sroot break; 5446000Sroot } 5456000Sroot if (!top) { 5466000Sroot if (!connected) 5476000Sroot longjmp(toplevel, 1); 5488378Ssam (void) mode(oldmode); 5496000Sroot } 5506000Sroot } 5516000Sroot 5526000Sroot /* 5536000Sroot * Telnet receiver states for fsm 5546000Sroot */ 5556000Sroot #define TS_DATA 0 5566000Sroot #define TS_IAC 1 5576000Sroot #define TS_WILL 2 5586000Sroot #define TS_WONT 3 5596000Sroot #define TS_DO 4 5606000Sroot #define TS_DONT 5 5616000Sroot 5626000Sroot telrcv() 5636000Sroot { 5646000Sroot register int c; 5656000Sroot static int state = TS_DATA; 5666000Sroot 5676000Sroot while (scc > 0) { 5686000Sroot c = *sbp++ & 0377, scc--; 5696000Sroot switch (state) { 5706000Sroot 5716000Sroot case TS_DATA: 5729972Ssam if (c == IAC) { 5736000Sroot state = TS_IAC; 5749972Ssam continue; 5759972Ssam } 5769972Ssam *tfrontp++ = c; 5779972Ssam /* 5789972Ssam * This hack is needed since we can't set 5799972Ssam * CRMOD on output only. Machines like MULTICS 5809972Ssam * like to send \r without \n; since we must 5819972Ssam * turn off CRMOD to get proper input, the mapping 5829972Ssam * is done here (sigh). 5839972Ssam */ 5849972Ssam if (c == '\r' && crmod) 5859972Ssam *tfrontp++ = '\n'; 5866000Sroot continue; 5876000Sroot 5886000Sroot case TS_IAC: 5896000Sroot switch (c) { 5906000Sroot 5916000Sroot case WILL: 5926000Sroot state = TS_WILL; 5936000Sroot continue; 5946000Sroot 5956000Sroot case WONT: 5966000Sroot state = TS_WONT; 5976000Sroot continue; 5986000Sroot 5996000Sroot case DO: 6006000Sroot state = TS_DO; 6016000Sroot continue; 6026000Sroot 6036000Sroot case DONT: 6046000Sroot state = TS_DONT; 6056000Sroot continue; 6066000Sroot 6076000Sroot case DM: 6086000Sroot ioctl(fileno(stdout), TIOCFLUSH, 0); 6096000Sroot break; 6106000Sroot 6116000Sroot case NOP: 6126000Sroot case GA: 6136000Sroot break; 6146000Sroot 6156000Sroot default: 6166000Sroot break; 6176000Sroot } 6186000Sroot state = TS_DATA; 6196000Sroot continue; 6206000Sroot 6216000Sroot case TS_WILL: 6228345Ssam printoption("RCVD", will, c, !hisopts[c]); 6236000Sroot if (!hisopts[c]) 6246000Sroot willoption(c); 6256000Sroot state = TS_DATA; 6266000Sroot continue; 6276000Sroot 6286000Sroot case TS_WONT: 6298345Ssam printoption("RCVD", wont, c, hisopts[c]); 6306000Sroot if (hisopts[c]) 6316000Sroot wontoption(c); 6326000Sroot state = TS_DATA; 6336000Sroot continue; 6346000Sroot 6356000Sroot case TS_DO: 6368345Ssam printoption("RCVD", doopt, c, !myopts[c]); 6376000Sroot if (!myopts[c]) 6386000Sroot dooption(c); 6396000Sroot state = TS_DATA; 6406000Sroot continue; 6416000Sroot 6426000Sroot case TS_DONT: 6438345Ssam printoption("RCVD", dont, c, myopts[c]); 6446000Sroot if (myopts[c]) { 6456000Sroot myopts[c] = 0; 6466000Sroot sprintf(nfrontp, wont, c); 6478378Ssam nfrontp += sizeof (wont) - 2; 6488345Ssam printoption("SENT", wont, c); 6496000Sroot } 6506000Sroot state = TS_DATA; 6516000Sroot continue; 6526000Sroot } 6536000Sroot } 6546000Sroot } 6556000Sroot 6566000Sroot willoption(option) 6576000Sroot int option; 6586000Sroot { 6596000Sroot char *fmt; 6606000Sroot 6616000Sroot switch (option) { 6626000Sroot 6636000Sroot case TELOPT_ECHO: 6648378Ssam (void) mode(1); 6656000Sroot 6666000Sroot case TELOPT_SGA: 6676000Sroot hisopts[option] = 1; 6686000Sroot fmt = doopt; 6696000Sroot break; 6706000Sroot 6716000Sroot case TELOPT_TM: 6726000Sroot fmt = dont; 6736000Sroot break; 6746000Sroot 6756000Sroot default: 6766000Sroot fmt = dont; 6776000Sroot break; 6786000Sroot } 6796024Ssam sprintf(nfrontp, fmt, option); 6808378Ssam nfrontp += sizeof (dont) - 2; 6818345Ssam printoption("SENT", fmt, option); 6826000Sroot } 6836000Sroot 6846000Sroot wontoption(option) 6856000Sroot int option; 6866000Sroot { 6876000Sroot char *fmt; 6886000Sroot 6896000Sroot switch (option) { 6906000Sroot 6916000Sroot case TELOPT_ECHO: 6928378Ssam (void) mode(2); 6936000Sroot 6946000Sroot case TELOPT_SGA: 6956000Sroot hisopts[option] = 0; 6966000Sroot fmt = dont; 6976000Sroot break; 6986000Sroot 6996000Sroot default: 7006000Sroot fmt = dont; 7016000Sroot } 7026000Sroot sprintf(nfrontp, fmt, option); 7038378Ssam nfrontp += sizeof (doopt) - 2; 7048345Ssam printoption("SENT", fmt, option); 7056000Sroot } 7066000Sroot 7076000Sroot dooption(option) 7086000Sroot int option; 7096000Sroot { 7106000Sroot char *fmt; 7116000Sroot 7126000Sroot switch (option) { 7136000Sroot 7146000Sroot case TELOPT_TM: 7156000Sroot fmt = wont; 7166000Sroot break; 7176000Sroot 71813231Ssam case TELOPT_ECHO: 71913231Ssam (void) mode(2); 72013231Ssam fmt = will; 72113231Ssam hisopts[option] = 0; 72213231Ssam break; 72313231Ssam 7246000Sroot case TELOPT_SGA: 7256000Sroot fmt = will; 7266000Sroot break; 7276000Sroot 7286000Sroot default: 7296000Sroot fmt = wont; 7306000Sroot break; 7316000Sroot } 7326000Sroot sprintf(nfrontp, fmt, option); 7338378Ssam nfrontp += sizeof (doopt) - 2; 7348345Ssam printoption("SENT", fmt, option); 7356000Sroot } 7366000Sroot 7376000Sroot /* 7386000Sroot * Set the escape character. 7396000Sroot */ 7406000Sroot setescape(argc, argv) 7416000Sroot int argc; 7426000Sroot char *argv[]; 7436000Sroot { 7446000Sroot register char *arg; 7456000Sroot char buf[50]; 7466000Sroot 7476000Sroot if (argc > 2) 7486000Sroot arg = argv[1]; 7496000Sroot else { 7506000Sroot printf("new escape character: "); 7516000Sroot gets(buf); 7526000Sroot arg = buf; 7536000Sroot } 7546000Sroot if (arg[0] != '\0') 7556000Sroot escape = arg[0]; 7566000Sroot printf("Escape character is '%s'.\n", control(escape)); 7579972Ssam fflush(stdout); 7586000Sroot } 7596000Sroot 7606024Ssam /*VARARGS*/ 7616024Ssam setoptions() 7626024Ssam { 7639972Ssam 7646024Ssam showoptions = !showoptions; 765*25289Skarels printf("%s show option processing.\n", showoptions ? "Will" : "Won't"); 7669972Ssam fflush(stdout); 7676024Ssam } 7686024Ssam 7699972Ssam /*VARARGS*/ 7709972Ssam setcrmod() 7719972Ssam { 7729972Ssam 7739972Ssam crmod = !crmod; 774*25289Skarels printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 7759972Ssam fflush(stdout); 7769972Ssam } 7779972Ssam 77810339Ssam /*VARARGS*/ 77910339Ssam setdebug() 78010339Ssam { 78110339Ssam 78217484Sleres debug = debug ? 0 : 1; 78310339Ssam printf("%s turn on socket level debugging.\n", 784*25289Skarels debug ? "Will" : "Won't"); 78510339Ssam fflush(stdout); 78617484Sleres if (net > 0 && 78717484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 78811758Ssam perror("setsockopt (SO_DEBUG)"); 78910339Ssam } 79010339Ssam 79117922Sralph sendesc() 79217922Sralph { 79317922Sralph *nfrontp++ = escape; 79417922Sralph } 79517922Sralph 79617922Sralph ayt() 79717922Sralph { 79817922Sralph *nfrontp++ = IAC; 79917922Sralph *nfrontp++ = AYT; 80017922Sralph } 80117922Sralph 80217922Sralph intp() 80317922Sralph { 80417922Sralph *nfrontp++ = IAC; 80517922Sralph *nfrontp++ = IP; 80617922Sralph } 80717922Sralph 8086000Sroot /* 8096000Sroot * Construct a control character sequence 8106000Sroot * for a special character. 8116000Sroot */ 8126000Sroot char * 8136000Sroot control(c) 8146000Sroot register int c; 8156000Sroot { 8166000Sroot static char buf[3]; 8176000Sroot 8186000Sroot if (c == 0177) 8196000Sroot return ("^?"); 8206000Sroot if (c >= 040) { 8216000Sroot buf[0] = c; 8226000Sroot buf[1] = 0; 8236000Sroot } else { 8246000Sroot buf[0] = '^'; 8256000Sroot buf[1] = '@'+c; 8266000Sroot buf[2] = 0; 8276000Sroot } 8286000Sroot return (buf); 8296000Sroot } 8306000Sroot 8316000Sroot struct cmd * 8326000Sroot getcmd(name) 8336000Sroot register char *name; 8346000Sroot { 8356000Sroot register char *p, *q; 8366000Sroot register struct cmd *c, *found; 8376000Sroot register int nmatches, longest; 8386000Sroot 8396000Sroot longest = 0; 8406000Sroot nmatches = 0; 8416000Sroot found = 0; 8426000Sroot for (c = cmdtab; p = c->name; c++) { 8436000Sroot for (q = name; *q == *p++; q++) 8446000Sroot if (*q == 0) /* exact match? */ 8456000Sroot return (c); 8466000Sroot if (!*q) { /* the name was a prefix */ 8476000Sroot if (q - name > longest) { 8486000Sroot longest = q - name; 8496000Sroot nmatches = 1; 8506000Sroot found = c; 8516000Sroot } else if (q - name == longest) 8526000Sroot nmatches++; 8536000Sroot } 8546000Sroot } 8556000Sroot if (nmatches > 1) 8566000Sroot return ((struct cmd *)-1); 8576000Sroot return (found); 8586000Sroot } 8596000Sroot 8606000Sroot deadpeer() 8616000Sroot { 8628378Ssam (void) mode(0); 8636000Sroot longjmp(peerdied, -1); 8646000Sroot } 8656000Sroot 8666000Sroot intr() 8676000Sroot { 8688378Ssam (void) mode(0); 8696000Sroot longjmp(toplevel, -1); 8706000Sroot } 8716000Sroot 8726000Sroot ttyflush(fd) 8736000Sroot { 8746000Sroot int n; 8756000Sroot 8766000Sroot if ((n = tfrontp - tbackp) > 0) 8776000Sroot n = write(fd, tbackp, n); 8788345Ssam if (n < 0) 8798345Ssam return; 8806000Sroot tbackp += n; 8816000Sroot if (tbackp == tfrontp) 8826000Sroot tbackp = tfrontp = ttyobuf; 8836000Sroot } 8846000Sroot 8856000Sroot netflush(fd) 8866000Sroot { 8876000Sroot int n; 8886000Sroot 8896000Sroot if ((n = nfrontp - nbackp) > 0) 8906000Sroot n = write(fd, nbackp, n); 8916501Ssam if (n < 0) { 8926501Ssam if (errno != ENOBUFS && errno != EWOULDBLOCK) { 8938378Ssam (void) mode(0); 8948377Ssam perror(hostname); 8956501Ssam close(fd); 8966501Ssam longjmp(peerdied, -1); 8976501Ssam /*NOTREACHED*/ 8986501Ssam } 8996000Sroot n = 0; 9006501Ssam } 9016000Sroot nbackp += n; 9026000Sroot if (nbackp == nfrontp) 9036000Sroot nbackp = nfrontp = netobuf; 9046000Sroot } 9056024Ssam 9066293Sroot /*VARARGS*/ 9076293Sroot printoption(direction, fmt, option, what) 9086024Ssam char *direction, *fmt; 9096293Sroot int option, what; 9106024Ssam { 9118345Ssam if (!showoptions) 9128345Ssam return; 9136024Ssam printf("%s ", direction); 9146024Ssam if (fmt == doopt) 9156024Ssam fmt = "do"; 9166024Ssam else if (fmt == dont) 9176024Ssam fmt = "dont"; 9186024Ssam else if (fmt == will) 9196024Ssam fmt = "will"; 9206024Ssam else if (fmt == wont) 9216024Ssam fmt = "wont"; 9226024Ssam else 9236024Ssam fmt = "???"; 9246024Ssam if (option < TELOPT_SUPDUP) 9256293Sroot printf("%s %s", fmt, telopts[option]); 9266024Ssam else 9276293Sroot printf("%s %d", fmt, option); 9286293Sroot if (*direction == '<') { 9296293Sroot printf("\r\n"); 9306293Sroot return; 9316293Sroot } 9326293Sroot printf(" (%s)\r\n", what ? "reply" : "don't reply"); 9336024Ssam } 934