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*25800Slepreau static char sccsid[] = "@(#)telnet.c 5.4 (Berkeley) 01/10/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)); 23725425Skarels continue; 23825425Skarels } 2399217Ssam perror("telnet: connect"); 24012989Ssam signal(SIGINT, SIG_DFL); 2416000Sroot return; 2426000Sroot } 2436000Sroot connected++; 2446000Sroot call(status, "status", 0); 2456000Sroot if (setjmp(peerdied) == 0) 2466000Sroot telnet(net); 2476000Sroot fprintf(stderr, "Connection closed by foreign host.\n"); 2486000Sroot exit(1); 2496000Sroot } 2506000Sroot 2516000Sroot /* 2526000Sroot * Print status about the connection. 2536000Sroot */ 2546000Sroot /*VARARGS*/ 2556000Sroot status() 2566000Sroot { 2576000Sroot if (connected) 2588377Ssam printf("Connected to %s.\n", hostname); 2596000Sroot else 2606000Sroot printf("No connection.\n"); 2616000Sroot printf("Escape character is '%s'.\n", control(escape)); 2629972Ssam fflush(stdout); 2636000Sroot } 2646000Sroot 2656000Sroot makeargv() 2666000Sroot { 2676000Sroot register char *cp; 2686000Sroot register char **argp = margv; 2696000Sroot 2706000Sroot margc = 0; 2716000Sroot for (cp = line; *cp;) { 2726000Sroot while (isspace(*cp)) 2736000Sroot cp++; 2746000Sroot if (*cp == '\0') 2756000Sroot break; 2766000Sroot *argp++ = cp; 2776000Sroot margc += 1; 2786000Sroot while (*cp != '\0' && !isspace(*cp)) 2796000Sroot cp++; 2806000Sroot if (*cp == '\0') 2816000Sroot break; 2826000Sroot *cp++ = '\0'; 2836000Sroot } 2846000Sroot *argp++ = 0; 2856000Sroot } 2866000Sroot 2876000Sroot /*VARARGS*/ 2886000Sroot suspend() 2896000Sroot { 2906000Sroot register int save; 2916000Sroot 2926000Sroot save = mode(0); 2938378Ssam kill(0, SIGTSTP); 2948378Ssam /* reget parameters in case they were changed */ 29513076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 29613076Ssam ioctl(0, TIOCGETC, (char *)&otc); 29713076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 2988378Ssam (void) mode(save); 2996000Sroot } 3006000Sroot 3016000Sroot /*VARARGS*/ 3026000Sroot bye() 3036000Sroot { 3048378Ssam register char *op; 3056000Sroot 3068378Ssam (void) mode(0); 3076000Sroot if (connected) { 30811758Ssam shutdown(net, 2); 3096000Sroot printf("Connection closed.\n"); 3106000Sroot close(net); 3116000Sroot connected = 0; 3128378Ssam /* reset his options */ 3138378Ssam for (op = hisopts; op < &hisopts[256]; op++) 3148378Ssam *op = 0; 3156000Sroot } 3166000Sroot } 3176000Sroot 3186000Sroot /*VARARGS*/ 3196000Sroot quit() 3206000Sroot { 3216000Sroot call(bye, "bye", 0); 3226000Sroot exit(0); 3236000Sroot } 3246000Sroot 3256000Sroot /* 3266000Sroot * Help command. 3276000Sroot */ 3286000Sroot help(argc, argv) 3296000Sroot int argc; 3306000Sroot char *argv[]; 3316000Sroot { 3326000Sroot register struct cmd *c; 3336000Sroot 3346000Sroot if (argc == 1) { 3356000Sroot printf("Commands may be abbreviated. Commands are:\n\n"); 3366000Sroot for (c = cmdtab; c->name; c++) 3376000Sroot printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 3386000Sroot return; 3396000Sroot } 3406000Sroot while (--argc > 0) { 3416000Sroot register char *arg; 3426000Sroot arg = *++argv; 3436000Sroot c = getcmd(arg); 3446000Sroot if (c == (struct cmd *)-1) 3456000Sroot printf("?Ambiguous help command %s\n", arg); 3466000Sroot else if (c == (struct cmd *)0) 3476000Sroot printf("?Invalid help command %s\n", arg); 3486000Sroot else 3496000Sroot printf("%s\n", c->help); 3506000Sroot } 3516000Sroot } 3526000Sroot 3536000Sroot /* 3546000Sroot * Call routine with argc, argv set from args (terminated by 0). 3556000Sroot * VARARGS2 3566000Sroot */ 3576000Sroot call(routine, args) 3586000Sroot int (*routine)(); 3596000Sroot int args; 3606000Sroot { 3616000Sroot register int *argp; 3626000Sroot register int argc; 3636000Sroot 3646000Sroot for (argc = 0, argp = &args; *argp++ != 0; argc++) 3656000Sroot ; 3666000Sroot (*routine)(argc, &args); 3676000Sroot } 3686000Sroot 36913076Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 37013076Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3719972Ssam 3726000Sroot mode(f) 3736000Sroot register int f; 3746000Sroot { 3758378Ssam static int prevmode = 0; 37613076Ssam struct tchars *tc; 37713076Ssam struct ltchars *ltc; 37813076Ssam struct sgttyb sb; 37913076Ssam int onoff, old; 3806000Sroot 3818378Ssam if (prevmode == f) 3828378Ssam return (f); 3838378Ssam old = prevmode; 3848378Ssam prevmode = f; 38513076Ssam sb = ottyb; 3866000Sroot switch (f) { 3878378Ssam 3886000Sroot case 0: 3896000Sroot onoff = 0; 3909972Ssam tc = &otc; 39113076Ssam ltc = &oltc; 3926000Sroot break; 3936000Sroot 3946000Sroot case 1: 3956000Sroot case 2: 39613076Ssam sb.sg_flags |= CBREAK; 3978378Ssam if (f == 1) 39813076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 3998378Ssam else 40013076Ssam sb.sg_flags |= ECHO|CRMOD; 40113076Ssam sb.sg_erase = sb.sg_kill = -1; 4029972Ssam tc = ¬c; 40313076Ssam ltc = &noltc; 4046000Sroot onoff = 1; 4059972Ssam break; 4069972Ssam 4079972Ssam default: 4089972Ssam return; 4096000Sroot } 41013076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 41113076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 41213076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 4136000Sroot ioctl(fileno(stdin), FIONBIO, &onoff); 4146000Sroot ioctl(fileno(stdout), FIONBIO, &onoff); 4156000Sroot return (old); 4166000Sroot } 4176000Sroot 4186000Sroot char sibuf[BUFSIZ], *sbp; 4196000Sroot char tibuf[BUFSIZ], *tbp; 4206000Sroot int scc, tcc; 4216000Sroot 4226000Sroot /* 4236000Sroot * Select from tty and network... 4246000Sroot */ 4256000Sroot telnet(s) 4266000Sroot int s; 4276000Sroot { 4286000Sroot register int c; 4296000Sroot int tin = fileno(stdin), tout = fileno(stdout); 4306000Sroot int on = 1; 4316000Sroot 4328378Ssam (void) mode(2); 4336000Sroot ioctl(s, FIONBIO, &on); 43425289Skarels if (telnetport && !hisopts[TELOPT_SGA]) 43517922Sralph willoption(TELOPT_SGA); 4366000Sroot for (;;) { 4376000Sroot int ibits = 0, obits = 0; 4386000Sroot 4396000Sroot if (nfrontp - nbackp) 4406000Sroot obits |= (1 << s); 4416000Sroot else 4426000Sroot ibits |= (1 << tin); 4436000Sroot if (tfrontp - tbackp) 4446000Sroot obits |= (1 << tout); 4456000Sroot else 4466000Sroot ibits |= (1 << s); 4476000Sroot if (scc < 0 && tcc < 0) 4486000Sroot break; 4499217Ssam select(16, &ibits, &obits, 0, 0); 4506000Sroot if (ibits == 0 && obits == 0) { 4516000Sroot sleep(5); 4526000Sroot continue; 4536000Sroot } 4546000Sroot 4556000Sroot /* 4566000Sroot * Something to read from the network... 4576000Sroot */ 4586000Sroot if (ibits & (1 << s)) { 4598378Ssam scc = read(s, sibuf, sizeof (sibuf)); 4606000Sroot if (scc < 0 && errno == EWOULDBLOCK) 4616000Sroot scc = 0; 4626000Sroot else { 4636000Sroot if (scc <= 0) 4646000Sroot break; 4656000Sroot sbp = sibuf; 4666000Sroot } 4676000Sroot } 4686000Sroot 4696000Sroot /* 4706000Sroot * Something to read from the tty... 4716000Sroot */ 4726000Sroot if (ibits & (1 << tin)) { 4738378Ssam tcc = read(tin, tibuf, sizeof (tibuf)); 4746000Sroot if (tcc < 0 && errno == EWOULDBLOCK) 4756000Sroot tcc = 0; 4766000Sroot else { 4776000Sroot if (tcc <= 0) 4786000Sroot break; 4796000Sroot tbp = tibuf; 4806000Sroot } 4816000Sroot } 4826000Sroot 4836000Sroot while (tcc > 0) { 4846000Sroot register int c; 4856000Sroot 4866000Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 4876000Sroot break; 4886000Sroot c = *tbp++ & 0377, tcc--; 4896000Sroot if (strip(c) == escape) { 4906000Sroot command(0); 4916000Sroot tcc = 0; 4926000Sroot break; 4936000Sroot } 49417922Sralph switch (c) { 49517922Sralph case '\n': 49617922Sralph if (!hisopts[TELOPT_ECHO]) 49717922Sralph *nfrontp++ = '\r'; 49817922Sralph *nfrontp++ = '\n'; 49917922Sralph break; 50017922Sralph case '\r': 50117922Sralph *nfrontp++ = '\r'; 50217922Sralph if (hisopts[TELOPT_ECHO]) 50317922Sralph *nfrontp++ = '\n'; 50417922Sralph else 50517922Sralph *nfrontp++ = '\0'; 50617922Sralph break; 50717922Sralph case IAC: 50817922Sralph *nfrontp++ = IAC; 50917922Sralph /* fall into ... */ 51017922Sralph default: 51111758Ssam *nfrontp++ = c; 51217922Sralph break; 51317922Sralph } 5146000Sroot } 5156000Sroot if ((obits & (1 << s)) && (nfrontp - nbackp) > 0) 5166000Sroot netflush(s); 5176000Sroot if (scc > 0) 5186000Sroot telrcv(); 5196000Sroot if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0) 5206000Sroot ttyflush(tout); 5216000Sroot } 5228378Ssam (void) mode(0); 5236000Sroot } 5246000Sroot 5256000Sroot command(top) 5266000Sroot int top; 5276000Sroot { 5286000Sroot register struct cmd *c; 5296000Sroot int oldmode, wasopen; 5306000Sroot 5316000Sroot oldmode = mode(0); 5326000Sroot if (!top) 5336000Sroot putchar('\n'); 5346000Sroot else 53512989Ssam signal(SIGINT, SIG_DFL); 5366000Sroot for (;;) { 5376000Sroot printf("%s> ", prompt); 53813997Ssam if (gets(line) == 0) { 539*25800Slepreau if (feof(stdin)) 540*25800Slepreau quit(); 5416000Sroot break; 54213997Ssam } 5436000Sroot if (line[0] == 0) 5446000Sroot break; 5456000Sroot makeargv(); 5466000Sroot c = getcmd(margv[0]); 5476000Sroot if (c == (struct cmd *)-1) { 5486000Sroot printf("?Ambiguous command\n"); 5496000Sroot continue; 5506000Sroot } 5516000Sroot if (c == 0) { 5526000Sroot printf("?Invalid command\n"); 5536000Sroot continue; 5546000Sroot } 5556000Sroot (*c->handler)(margc, margv); 5566000Sroot if (c->handler != help) 5576000Sroot break; 5586000Sroot } 5596000Sroot if (!top) { 5606000Sroot if (!connected) 5616000Sroot longjmp(toplevel, 1); 5628378Ssam (void) mode(oldmode); 5636000Sroot } 5646000Sroot } 5656000Sroot 5666000Sroot /* 5676000Sroot * Telnet receiver states for fsm 5686000Sroot */ 5696000Sroot #define TS_DATA 0 5706000Sroot #define TS_IAC 1 5716000Sroot #define TS_WILL 2 5726000Sroot #define TS_WONT 3 5736000Sroot #define TS_DO 4 5746000Sroot #define TS_DONT 5 5756000Sroot 5766000Sroot telrcv() 5776000Sroot { 5786000Sroot register int c; 5796000Sroot static int state = TS_DATA; 5806000Sroot 5816000Sroot while (scc > 0) { 5826000Sroot c = *sbp++ & 0377, scc--; 5836000Sroot switch (state) { 5846000Sroot 5856000Sroot case TS_DATA: 5869972Ssam if (c == IAC) { 5876000Sroot state = TS_IAC; 5889972Ssam continue; 5899972Ssam } 5909972Ssam *tfrontp++ = c; 5919972Ssam /* 5929972Ssam * This hack is needed since we can't set 5939972Ssam * CRMOD on output only. Machines like MULTICS 5949972Ssam * like to send \r without \n; since we must 5959972Ssam * turn off CRMOD to get proper input, the mapping 5969972Ssam * is done here (sigh). 5979972Ssam */ 5989972Ssam if (c == '\r' && crmod) 5999972Ssam *tfrontp++ = '\n'; 6006000Sroot continue; 6016000Sroot 6026000Sroot case TS_IAC: 6036000Sroot switch (c) { 6046000Sroot 6056000Sroot case WILL: 6066000Sroot state = TS_WILL; 6076000Sroot continue; 6086000Sroot 6096000Sroot case WONT: 6106000Sroot state = TS_WONT; 6116000Sroot continue; 6126000Sroot 6136000Sroot case DO: 6146000Sroot state = TS_DO; 6156000Sroot continue; 6166000Sroot 6176000Sroot case DONT: 6186000Sroot state = TS_DONT; 6196000Sroot continue; 6206000Sroot 6216000Sroot case DM: 6226000Sroot ioctl(fileno(stdout), TIOCFLUSH, 0); 6236000Sroot break; 6246000Sroot 6256000Sroot case NOP: 6266000Sroot case GA: 6276000Sroot break; 6286000Sroot 6296000Sroot default: 6306000Sroot break; 6316000Sroot } 6326000Sroot state = TS_DATA; 6336000Sroot continue; 6346000Sroot 6356000Sroot case TS_WILL: 6368345Ssam printoption("RCVD", will, c, !hisopts[c]); 6376000Sroot if (!hisopts[c]) 6386000Sroot willoption(c); 6396000Sroot state = TS_DATA; 6406000Sroot continue; 6416000Sroot 6426000Sroot case TS_WONT: 6438345Ssam printoption("RCVD", wont, c, hisopts[c]); 6446000Sroot if (hisopts[c]) 6456000Sroot wontoption(c); 6466000Sroot state = TS_DATA; 6476000Sroot continue; 6486000Sroot 6496000Sroot case TS_DO: 6508345Ssam printoption("RCVD", doopt, c, !myopts[c]); 6516000Sroot if (!myopts[c]) 6526000Sroot dooption(c); 6536000Sroot state = TS_DATA; 6546000Sroot continue; 6556000Sroot 6566000Sroot case TS_DONT: 6578345Ssam printoption("RCVD", dont, c, myopts[c]); 6586000Sroot if (myopts[c]) { 6596000Sroot myopts[c] = 0; 6606000Sroot sprintf(nfrontp, wont, c); 6618378Ssam nfrontp += sizeof (wont) - 2; 6628345Ssam printoption("SENT", wont, c); 6636000Sroot } 6646000Sroot state = TS_DATA; 6656000Sroot continue; 6666000Sroot } 6676000Sroot } 6686000Sroot } 6696000Sroot 6706000Sroot willoption(option) 6716000Sroot int option; 6726000Sroot { 6736000Sroot char *fmt; 6746000Sroot 6756000Sroot switch (option) { 6766000Sroot 6776000Sroot case TELOPT_ECHO: 6788378Ssam (void) mode(1); 6796000Sroot 6806000Sroot case TELOPT_SGA: 6816000Sroot hisopts[option] = 1; 6826000Sroot fmt = doopt; 6836000Sroot break; 6846000Sroot 6856000Sroot case TELOPT_TM: 6866000Sroot fmt = dont; 6876000Sroot break; 6886000Sroot 6896000Sroot default: 6906000Sroot fmt = dont; 6916000Sroot break; 6926000Sroot } 6936024Ssam sprintf(nfrontp, fmt, option); 6948378Ssam nfrontp += sizeof (dont) - 2; 6958345Ssam printoption("SENT", fmt, option); 6966000Sroot } 6976000Sroot 6986000Sroot wontoption(option) 6996000Sroot int option; 7006000Sroot { 7016000Sroot char *fmt; 7026000Sroot 7036000Sroot switch (option) { 7046000Sroot 7056000Sroot case TELOPT_ECHO: 7068378Ssam (void) mode(2); 7076000Sroot 7086000Sroot case TELOPT_SGA: 7096000Sroot hisopts[option] = 0; 7106000Sroot fmt = dont; 7116000Sroot break; 7126000Sroot 7136000Sroot default: 7146000Sroot fmt = dont; 7156000Sroot } 7166000Sroot sprintf(nfrontp, fmt, option); 7178378Ssam nfrontp += sizeof (doopt) - 2; 7188345Ssam printoption("SENT", fmt, option); 7196000Sroot } 7206000Sroot 7216000Sroot dooption(option) 7226000Sroot int option; 7236000Sroot { 7246000Sroot char *fmt; 7256000Sroot 7266000Sroot switch (option) { 7276000Sroot 7286000Sroot case TELOPT_TM: 7296000Sroot fmt = wont; 7306000Sroot break; 7316000Sroot 73213231Ssam case TELOPT_ECHO: 73313231Ssam (void) mode(2); 73413231Ssam fmt = will; 73513231Ssam hisopts[option] = 0; 73613231Ssam break; 73713231Ssam 7386000Sroot case TELOPT_SGA: 7396000Sroot fmt = will; 7406000Sroot break; 7416000Sroot 7426000Sroot default: 7436000Sroot fmt = wont; 7446000Sroot break; 7456000Sroot } 7466000Sroot sprintf(nfrontp, fmt, option); 7478378Ssam nfrontp += sizeof (doopt) - 2; 7488345Ssam printoption("SENT", fmt, option); 7496000Sroot } 7506000Sroot 7516000Sroot /* 7526000Sroot * Set the escape character. 7536000Sroot */ 7546000Sroot setescape(argc, argv) 7556000Sroot int argc; 7566000Sroot char *argv[]; 7576000Sroot { 7586000Sroot register char *arg; 7596000Sroot char buf[50]; 7606000Sroot 7616000Sroot if (argc > 2) 7626000Sroot arg = argv[1]; 7636000Sroot else { 7646000Sroot printf("new escape character: "); 7656000Sroot gets(buf); 7666000Sroot arg = buf; 7676000Sroot } 7686000Sroot if (arg[0] != '\0') 7696000Sroot escape = arg[0]; 7706000Sroot printf("Escape character is '%s'.\n", control(escape)); 7719972Ssam fflush(stdout); 7726000Sroot } 7736000Sroot 7746024Ssam /*VARARGS*/ 7756024Ssam setoptions() 7766024Ssam { 7779972Ssam 7786024Ssam showoptions = !showoptions; 77925289Skarels printf("%s show option processing.\n", showoptions ? "Will" : "Won't"); 7809972Ssam fflush(stdout); 7816024Ssam } 7826024Ssam 7839972Ssam /*VARARGS*/ 7849972Ssam setcrmod() 7859972Ssam { 7869972Ssam 7879972Ssam crmod = !crmod; 78825289Skarels printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 7899972Ssam fflush(stdout); 7909972Ssam } 7919972Ssam 79210339Ssam /*VARARGS*/ 79310339Ssam setdebug() 79410339Ssam { 79510339Ssam 79617484Sleres debug = debug ? 0 : 1; 79710339Ssam printf("%s turn on socket level debugging.\n", 79825289Skarels debug ? "Will" : "Won't"); 79910339Ssam fflush(stdout); 80017484Sleres if (net > 0 && 80117484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 80211758Ssam perror("setsockopt (SO_DEBUG)"); 80310339Ssam } 80410339Ssam 80517922Sralph sendesc() 80617922Sralph { 80717922Sralph *nfrontp++ = escape; 80817922Sralph } 80917922Sralph 81017922Sralph ayt() 81117922Sralph { 81217922Sralph *nfrontp++ = IAC; 81317922Sralph *nfrontp++ = AYT; 81417922Sralph } 81517922Sralph 81617922Sralph intp() 81717922Sralph { 81817922Sralph *nfrontp++ = IAC; 81917922Sralph *nfrontp++ = IP; 82017922Sralph } 82117922Sralph 8226000Sroot /* 8236000Sroot * Construct a control character sequence 8246000Sroot * for a special character. 8256000Sroot */ 8266000Sroot char * 8276000Sroot control(c) 8286000Sroot register int c; 8296000Sroot { 8306000Sroot static char buf[3]; 8316000Sroot 8326000Sroot if (c == 0177) 8336000Sroot return ("^?"); 8346000Sroot if (c >= 040) { 8356000Sroot buf[0] = c; 8366000Sroot buf[1] = 0; 8376000Sroot } else { 8386000Sroot buf[0] = '^'; 8396000Sroot buf[1] = '@'+c; 8406000Sroot buf[2] = 0; 8416000Sroot } 8426000Sroot return (buf); 8436000Sroot } 8446000Sroot 8456000Sroot struct cmd * 8466000Sroot getcmd(name) 8476000Sroot register char *name; 8486000Sroot { 8496000Sroot register char *p, *q; 8506000Sroot register struct cmd *c, *found; 8516000Sroot register int nmatches, longest; 8526000Sroot 8536000Sroot longest = 0; 8546000Sroot nmatches = 0; 8556000Sroot found = 0; 8566000Sroot for (c = cmdtab; p = c->name; c++) { 8576000Sroot for (q = name; *q == *p++; q++) 8586000Sroot if (*q == 0) /* exact match? */ 8596000Sroot return (c); 8606000Sroot if (!*q) { /* the name was a prefix */ 8616000Sroot if (q - name > longest) { 8626000Sroot longest = q - name; 8636000Sroot nmatches = 1; 8646000Sroot found = c; 8656000Sroot } else if (q - name == longest) 8666000Sroot nmatches++; 8676000Sroot } 8686000Sroot } 8696000Sroot if (nmatches > 1) 8706000Sroot return ((struct cmd *)-1); 8716000Sroot return (found); 8726000Sroot } 8736000Sroot 8746000Sroot deadpeer() 8756000Sroot { 8768378Ssam (void) mode(0); 8776000Sroot longjmp(peerdied, -1); 8786000Sroot } 8796000Sroot 8806000Sroot intr() 8816000Sroot { 8828378Ssam (void) mode(0); 8836000Sroot longjmp(toplevel, -1); 8846000Sroot } 8856000Sroot 8866000Sroot ttyflush(fd) 8876000Sroot { 8886000Sroot int n; 8896000Sroot 8906000Sroot if ((n = tfrontp - tbackp) > 0) 8916000Sroot n = write(fd, tbackp, n); 8928345Ssam if (n < 0) 8938345Ssam return; 8946000Sroot tbackp += n; 8956000Sroot if (tbackp == tfrontp) 8966000Sroot tbackp = tfrontp = ttyobuf; 8976000Sroot } 8986000Sroot 8996000Sroot netflush(fd) 9006000Sroot { 9016000Sroot int n; 9026000Sroot 9036000Sroot if ((n = nfrontp - nbackp) > 0) 9046000Sroot n = write(fd, nbackp, n); 9056501Ssam if (n < 0) { 9066501Ssam if (errno != ENOBUFS && errno != EWOULDBLOCK) { 9078378Ssam (void) mode(0); 9088377Ssam perror(hostname); 9096501Ssam close(fd); 9106501Ssam longjmp(peerdied, -1); 9116501Ssam /*NOTREACHED*/ 9126501Ssam } 9136000Sroot n = 0; 9146501Ssam } 9156000Sroot nbackp += n; 9166000Sroot if (nbackp == nfrontp) 9176000Sroot nbackp = nfrontp = netobuf; 9186000Sroot } 9196024Ssam 9206293Sroot /*VARARGS*/ 9216293Sroot printoption(direction, fmt, option, what) 9226024Ssam char *direction, *fmt; 9236293Sroot int option, what; 9246024Ssam { 9258345Ssam if (!showoptions) 9268345Ssam return; 9276024Ssam printf("%s ", direction); 9286024Ssam if (fmt == doopt) 9296024Ssam fmt = "do"; 9306024Ssam else if (fmt == dont) 9316024Ssam fmt = "dont"; 9326024Ssam else if (fmt == will) 9336024Ssam fmt = "will"; 9346024Ssam else if (fmt == wont) 9356024Ssam fmt = "wont"; 9366024Ssam else 9376024Ssam fmt = "???"; 9386024Ssam if (option < TELOPT_SUPDUP) 9396293Sroot printf("%s %s", fmt, telopts[option]); 9406024Ssam else 9416293Sroot printf("%s %d", fmt, option); 9426293Sroot if (*direction == '<') { 9436293Sroot printf("\r\n"); 9446293Sroot return; 9456293Sroot } 9466293Sroot printf(" (%s)\r\n", what ? "reply" : "don't reply"); 9476024Ssam } 948