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*27021Sminshall static char sccsid[] = "@(#)telnet.c 5.6 (Berkeley) 04/09/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; 55*27021Sminshall int printnet = 0; 56*27021Sminshall static FILE *NetTrace; 5725289Skarels int telnetport = 1; 586000Sroot char *prompt; 599972Ssam char escape = CTRL(]); 606000Sroot 616000Sroot char line[200]; 626000Sroot int margc; 636000Sroot char *margv[20]; 646000Sroot 656000Sroot jmp_buf toplevel; 666000Sroot jmp_buf peerdied; 676000Sroot 686000Sroot extern int errno; 696000Sroot 706000Sroot int tn(), quit(), suspend(), bye(), help(); 716024Ssam int setescape(), status(), toggle(), setoptions(); 7217922Sralph int setcrmod(), setdebug(), sendesc(), ayt(), intp(); 73*27021Sminshall int setprintnet(); 746000Sroot 758378Ssam #define HELPINDENT (sizeof ("connect")) 766000Sroot 776000Sroot struct cmd { 7811758Ssam char *name; /* command name */ 7911758Ssam char *help; /* help string */ 8011758Ssam int (*handler)(); /* routine which executes command */ 81*27021Sminshall int dohelp; /* Should we give general help information? */ 826000Sroot }; 836000Sroot 8411758Ssam char openhelp[] = "connect to a site"; 8511758Ssam char closehelp[] = "close current connection"; 8611758Ssam char quithelp[] = "exit telnet"; 8711758Ssam char zhelp[] = "suspend telnet"; 8811758Ssam char debughelp[] = "toggle debugging"; 8911758Ssam char escapehelp[] = "set escape character"; 9011758Ssam char statushelp[] = "print status information"; 9111758Ssam char helphelp[] = "print help information"; 9211758Ssam char optionshelp[] = "toggle viewing of options processing"; 9311758Ssam char crmodhelp[] = "toggle mapping of received carriage returns"; 9417922Sralph char sendeschelp[] = "send escape character"; 9525289Skarels char aythelp[] = "send \"Are You There\""; 9625289Skarels char intphelp[] = "send \"Interrupt Process\""; 97*27021Sminshall char printnethelp[] ="toggle printing of raw network data"; 986000Sroot 996000Sroot struct cmd cmdtab[] = { 100*27021Sminshall { "open", openhelp, tn, 1 }, 101*27021Sminshall { "close", closehelp, bye, 1 }, 102*27021Sminshall { "quit", quithelp, quit, 1 }, 103*27021Sminshall { "z", zhelp, suspend, 1 }, 104*27021Sminshall { "escape", escapehelp, setescape, 1 }, 105*27021Sminshall { "status", statushelp, status, 1 }, 106*27021Sminshall { "crmod", crmodhelp, setcrmod, 1 }, 107*27021Sminshall { "ayt", aythelp, ayt, 1 }, 108*27021Sminshall { "interrupt", intphelp, intp, 1 }, 109*27021Sminshall { "passthru", sendeschelp, sendesc, 1 }, 110*27021Sminshall { "help", helphelp, help, 1 }, 111*27021Sminshall { "?", helphelp, help, 0 }, 112*27021Sminshall { "options", optionshelp, setoptions, 0 }, 113*27021Sminshall { "debug", debughelp, setdebug, 0 }, 114*27021Sminshall { "printnet", printnethelp, setprintnet, 0 }, 1156000Sroot 0 1166000Sroot }; 1176000Sroot 1189972Ssam struct sockaddr_in sin; 1196000Sroot 1206000Sroot int intr(), deadpeer(); 1216000Sroot char *control(); 1226000Sroot struct cmd *getcmd(); 1238345Ssam struct servent *sp; 1246000Sroot 12513076Ssam struct tchars otc; 12613076Ssam struct ltchars oltc; 12713076Ssam struct sgttyb ottyb; 1288378Ssam 1296000Sroot main(argc, argv) 1306000Sroot int argc; 1316000Sroot char *argv[]; 1326000Sroot { 1338345Ssam sp = getservbyname("telnet", "tcp"); 1348345Ssam if (sp == 0) { 1358345Ssam fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 1368345Ssam exit(1); 1378345Ssam } 138*27021Sminshall NetTrace = stdout; 13913076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 14013076Ssam ioctl(0, TIOCGETC, (char *)&otc); 14113076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 1426000Sroot setbuf(stdin, 0); 1436000Sroot setbuf(stdout, 0); 1446000Sroot prompt = argv[0]; 14517484Sleres if (argc > 1 && !strcmp(argv[1], "-d")) { 14617484Sleres debug = 1; 14717484Sleres argv++; 14817484Sleres argc--; 14917484Sleres } 150*27021Sminshall if (argc > 1 && !strcmp(argv[1], "-n")) { 151*27021Sminshall argv++; 152*27021Sminshall argc--; 153*27021Sminshall if (argc > 1) { /* get file name */ 154*27021Sminshall NetTrace = fopen(argv[1], "w"); 155*27021Sminshall argv++; 156*27021Sminshall argc--; 157*27021Sminshall if (NetTrace == NULL) { 158*27021Sminshall NetTrace = stdout; 159*27021Sminshall } 160*27021Sminshall } 161*27021Sminshall } 1626000Sroot if (argc != 1) { 1636000Sroot if (setjmp(toplevel) != 0) 1646000Sroot exit(0); 1656000Sroot tn(argc, argv); 1666000Sroot } 1676000Sroot setjmp(toplevel); 1686000Sroot for (;;) 1696000Sroot command(1); 1706000Sroot } 1716000Sroot 1728377Ssam char *hostname; 1738377Ssam char hnamebuf[32]; 1746000Sroot 1756000Sroot tn(argc, argv) 1766000Sroot int argc; 1776000Sroot char *argv[]; 1786000Sroot { 1796000Sroot register int c; 18025425Skarels register struct hostent *host = 0; 1816000Sroot 1826000Sroot if (connected) { 1838377Ssam printf("?Already connected to %s\n", hostname); 1846000Sroot return; 1856000Sroot } 1866000Sroot if (argc < 2) { 1876000Sroot strcpy(line, "Connect "); 1886000Sroot printf("(to) "); 1896000Sroot gets(&line[strlen(line)]); 1906000Sroot makeargv(); 1916000Sroot argc = margc; 1926000Sroot argv = margv; 1936000Sroot } 1946000Sroot if (argc > 3) { 1956000Sroot printf("usage: %s host-name [port]\n", argv[0]); 1966000Sroot return; 1976000Sroot } 19825425Skarels sin.sin_addr.s_addr = inet_addr(argv[1]); 19925425Skarels if (sin.sin_addr.s_addr != -1) { 20025425Skarels sin.sin_family = AF_INET; 20125425Skarels strcpy(hnamebuf, argv[1]); 20225425Skarels hostname = hnamebuf; 2038377Ssam } else { 20425425Skarels host = gethostbyname(argv[1]); 20525425Skarels if (host) { 20625425Skarels sin.sin_family = host->h_addrtype; 20725425Skarels bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 20825425Skarels host->h_length); 20925425Skarels hostname = host->h_name; 21025425Skarels } else { 2118377Ssam printf("%s: unknown host\n", argv[1]); 2128377Ssam return; 2138377Ssam } 2146000Sroot } 2158345Ssam sin.sin_port = sp->s_port; 2166024Ssam if (argc == 3) { 2176024Ssam sin.sin_port = atoi(argv[2]); 21825289Skarels if (sin.sin_port <= 0) { 21925289Skarels sp = getservbyname(argv[2], "tcp"); 22025289Skarels if (sp) 22125289Skarels sin.sin_port = sp->s_port; 22225289Skarels else { 22325289Skarels printf("%s: bad port number\n", argv[2]); 22425289Skarels return; 22525289Skarels } 22625289Skarels } else { 22725289Skarels sin.sin_port = atoi(argv[2]); 22825289Skarels sin.sin_port = htons(sin.sin_port); 2296024Ssam } 23025289Skarels telnetport = 0; 2316024Ssam } 23212989Ssam signal(SIGINT, intr); 23312989Ssam signal(SIGPIPE, deadpeer); 2346000Sroot printf("Trying...\n"); 235*27021Sminshall do { 236*27021Sminshall net = socket(AF_INET, SOCK_STREAM, 0); 237*27021Sminshall if (net < 0) { 238*27021Sminshall perror("telnet: socket"); 239*27021Sminshall return; 240*27021Sminshall } 241*27021Sminshall if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, 242*27021Sminshall sizeof(debug)) < 0) 243*27021Sminshall perror("setsockopt (SO_DEBUG)"); 244*27021Sminshall if (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) { 245*27021Sminshall if (host && host->h_addr_list[1]) { 246*27021Sminshall int oerrno = errno; 24725425Skarels 248*27021Sminshall fprintf(stderr, 249*27021Sminshall "telnet: connect to address %s: ", 250*27021Sminshall inet_ntoa(sin.sin_addr)); 251*27021Sminshall errno = oerrno; 252*27021Sminshall perror(0); 253*27021Sminshall host->h_addr_list++; 254*27021Sminshall bcopy(host->h_addr_list[0], 255*27021Sminshall (caddr_t)&sin.sin_addr, host->h_length); 256*27021Sminshall fprintf(stderr, "Trying %s...\n", 257*27021Sminshall inet_ntoa(sin.sin_addr)); 258*27021Sminshall (void) close(net); 259*27021Sminshall continue; 26026814Skarels } 261*27021Sminshall perror("telnet: connect"); 262*27021Sminshall signal(SIGINT, SIG_DFL); 263*27021Sminshall return; 26425425Skarels } 265*27021Sminshall connected++; 266*27021Sminshall } while (connected == 0); 2676000Sroot call(status, "status", 0); 2686000Sroot if (setjmp(peerdied) == 0) 2696000Sroot telnet(net); 2706000Sroot fprintf(stderr, "Connection closed by foreign host.\n"); 2716000Sroot exit(1); 2726000Sroot } 2736000Sroot 2746000Sroot /* 2756000Sroot * Print status about the connection. 2766000Sroot */ 2776000Sroot /*VARARGS*/ 2786000Sroot status() 2796000Sroot { 2806000Sroot if (connected) 2818377Ssam printf("Connected to %s.\n", hostname); 2826000Sroot else 2836000Sroot printf("No connection.\n"); 2846000Sroot printf("Escape character is '%s'.\n", control(escape)); 2859972Ssam fflush(stdout); 2866000Sroot } 2876000Sroot 2886000Sroot makeargv() 2896000Sroot { 2906000Sroot register char *cp; 2916000Sroot register char **argp = margv; 2926000Sroot 2936000Sroot margc = 0; 2946000Sroot for (cp = line; *cp;) { 2956000Sroot while (isspace(*cp)) 2966000Sroot cp++; 2976000Sroot if (*cp == '\0') 2986000Sroot break; 2996000Sroot *argp++ = cp; 3006000Sroot margc += 1; 3016000Sroot while (*cp != '\0' && !isspace(*cp)) 3026000Sroot cp++; 3036000Sroot if (*cp == '\0') 3046000Sroot break; 3056000Sroot *cp++ = '\0'; 3066000Sroot } 3076000Sroot *argp++ = 0; 3086000Sroot } 3096000Sroot 3106000Sroot /*VARARGS*/ 3116000Sroot suspend() 3126000Sroot { 3136000Sroot register int save; 3146000Sroot 3156000Sroot save = mode(0); 3168378Ssam kill(0, SIGTSTP); 3178378Ssam /* reget parameters in case they were changed */ 31813076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 31913076Ssam ioctl(0, TIOCGETC, (char *)&otc); 32013076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 3218378Ssam (void) mode(save); 3226000Sroot } 3236000Sroot 3246000Sroot /*VARARGS*/ 3256000Sroot bye() 3266000Sroot { 3278378Ssam register char *op; 3286000Sroot 3298378Ssam (void) mode(0); 3306000Sroot if (connected) { 33111758Ssam shutdown(net, 2); 3326000Sroot printf("Connection closed.\n"); 3336000Sroot close(net); 3346000Sroot connected = 0; 3358378Ssam /* reset his options */ 3368378Ssam for (op = hisopts; op < &hisopts[256]; op++) 3378378Ssam *op = 0; 3386000Sroot } 3396000Sroot } 3406000Sroot 3416000Sroot /*VARARGS*/ 3426000Sroot quit() 3436000Sroot { 3446000Sroot call(bye, "bye", 0); 3456000Sroot exit(0); 3466000Sroot } 3476000Sroot 3486000Sroot /* 3496000Sroot * Help command. 3506000Sroot */ 3516000Sroot help(argc, argv) 3526000Sroot int argc; 3536000Sroot char *argv[]; 3546000Sroot { 3556000Sroot register struct cmd *c; 3566000Sroot 3576000Sroot if (argc == 1) { 3586000Sroot printf("Commands may be abbreviated. Commands are:\n\n"); 3596000Sroot for (c = cmdtab; c->name; c++) 360*27021Sminshall if (c->dohelp) { 361*27021Sminshall printf("%-*s\t%s\n", HELPINDENT, c->name, 362*27021Sminshall c->help); 363*27021Sminshall } 3646000Sroot return; 3656000Sroot } 3666000Sroot while (--argc > 0) { 3676000Sroot register char *arg; 3686000Sroot arg = *++argv; 3696000Sroot c = getcmd(arg); 3706000Sroot if (c == (struct cmd *)-1) 3716000Sroot printf("?Ambiguous help command %s\n", arg); 3726000Sroot else if (c == (struct cmd *)0) 3736000Sroot printf("?Invalid help command %s\n", arg); 3746000Sroot else 3756000Sroot printf("%s\n", c->help); 3766000Sroot } 3776000Sroot } 3786000Sroot 3796000Sroot /* 3806000Sroot * Call routine with argc, argv set from args (terminated by 0). 3816000Sroot * VARARGS2 3826000Sroot */ 3836000Sroot call(routine, args) 3846000Sroot int (*routine)(); 3856000Sroot int args; 3866000Sroot { 3876000Sroot register int *argp; 3886000Sroot register int argc; 3896000Sroot 3906000Sroot for (argc = 0, argp = &args; *argp++ != 0; argc++) 3916000Sroot ; 3926000Sroot (*routine)(argc, &args); 3936000Sroot } 3946000Sroot 39513076Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 39613076Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3979972Ssam 3986000Sroot mode(f) 3996000Sroot register int f; 4006000Sroot { 4018378Ssam static int prevmode = 0; 40213076Ssam struct tchars *tc; 40313076Ssam struct ltchars *ltc; 40413076Ssam struct sgttyb sb; 40513076Ssam int onoff, old; 4066000Sroot 4078378Ssam if (prevmode == f) 4088378Ssam return (f); 4098378Ssam old = prevmode; 4108378Ssam prevmode = f; 41113076Ssam sb = ottyb; 4126000Sroot switch (f) { 4138378Ssam 4146000Sroot case 0: 4156000Sroot onoff = 0; 4169972Ssam tc = &otc; 41713076Ssam ltc = &oltc; 4186000Sroot break; 4196000Sroot 4206000Sroot case 1: 4216000Sroot case 2: 42213076Ssam sb.sg_flags |= CBREAK; 4238378Ssam if (f == 1) 42413076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 4258378Ssam else 42613076Ssam sb.sg_flags |= ECHO|CRMOD; 42713076Ssam sb.sg_erase = sb.sg_kill = -1; 4289972Ssam tc = ¬c; 42913076Ssam ltc = &noltc; 4306000Sroot onoff = 1; 4319972Ssam break; 4329972Ssam 4339972Ssam default: 4349972Ssam return; 4356000Sroot } 43613076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 43713076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 43813076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 4396000Sroot ioctl(fileno(stdin), FIONBIO, &onoff); 4406000Sroot ioctl(fileno(stdout), FIONBIO, &onoff); 4416000Sroot return (old); 4426000Sroot } 4436000Sroot 4446000Sroot char sibuf[BUFSIZ], *sbp; 4456000Sroot char tibuf[BUFSIZ], *tbp; 4466000Sroot int scc, tcc; 4476000Sroot 4486000Sroot /* 4496000Sroot * Select from tty and network... 4506000Sroot */ 4516000Sroot telnet(s) 4526000Sroot int s; 4536000Sroot { 4546000Sroot register int c; 4556000Sroot int tin = fileno(stdin), tout = fileno(stdout); 4566000Sroot int on = 1; 4576000Sroot 4588378Ssam (void) mode(2); 4596000Sroot ioctl(s, FIONBIO, &on); 46025289Skarels if (telnetport && !hisopts[TELOPT_SGA]) 46117922Sralph willoption(TELOPT_SGA); 4626000Sroot for (;;) { 4636000Sroot int ibits = 0, obits = 0; 4646000Sroot 4656000Sroot if (nfrontp - nbackp) 4666000Sroot obits |= (1 << s); 4676000Sroot else 4686000Sroot ibits |= (1 << tin); 4696000Sroot if (tfrontp - tbackp) 4706000Sroot obits |= (1 << tout); 4716000Sroot else 4726000Sroot ibits |= (1 << s); 4736000Sroot if (scc < 0 && tcc < 0) 4746000Sroot break; 4759217Ssam select(16, &ibits, &obits, 0, 0); 4766000Sroot if (ibits == 0 && obits == 0) { 4776000Sroot sleep(5); 4786000Sroot continue; 4796000Sroot } 4806000Sroot 4816000Sroot /* 4826000Sroot * Something to read from the network... 4836000Sroot */ 4846000Sroot if (ibits & (1 << s)) { 4858378Ssam scc = read(s, sibuf, sizeof (sibuf)); 4866000Sroot if (scc < 0 && errno == EWOULDBLOCK) 4876000Sroot scc = 0; 4886000Sroot else { 4896000Sroot if (scc <= 0) 4906000Sroot break; 4916000Sroot sbp = sibuf; 492*27021Sminshall if (printnet) { 493*27021Sminshall Dump('<', sbp, scc); 494*27021Sminshall } 4956000Sroot } 4966000Sroot } 4976000Sroot 4986000Sroot /* 4996000Sroot * Something to read from the tty... 5006000Sroot */ 5016000Sroot if (ibits & (1 << tin)) { 5028378Ssam tcc = read(tin, tibuf, sizeof (tibuf)); 5036000Sroot if (tcc < 0 && errno == EWOULDBLOCK) 5046000Sroot tcc = 0; 5056000Sroot else { 5066000Sroot if (tcc <= 0) 5076000Sroot break; 5086000Sroot tbp = tibuf; 5096000Sroot } 5106000Sroot } 5116000Sroot 5126000Sroot while (tcc > 0) { 5136000Sroot register int c; 5146000Sroot 5156000Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 5166000Sroot break; 5176000Sroot c = *tbp++ & 0377, tcc--; 5186000Sroot if (strip(c) == escape) { 5196000Sroot command(0); 5206000Sroot tcc = 0; 5216000Sroot break; 5226000Sroot } 52317922Sralph switch (c) { 524*27021Sminshall case '\n'|0x80: 52517922Sralph case '\n': 526*27021Sminshall /* 527*27021Sminshall * If echoing is happening locally, 528*27021Sminshall * then a newline (unix) is CRLF (TELNET). 529*27021Sminshall */ 53017922Sralph if (!hisopts[TELOPT_ECHO]) 53117922Sralph *nfrontp++ = '\r'; 53217922Sralph *nfrontp++ = '\n'; 53317922Sralph break; 534*27021Sminshall case '\r'|0x80: 53517922Sralph case '\r': 53617922Sralph *nfrontp++ = '\r'; 537*27021Sminshall *nfrontp++ = '\0'; 53817922Sralph break; 53917922Sralph case IAC: 54017922Sralph *nfrontp++ = IAC; 541*27021Sminshall *nfrontp++ = IAC; 542*27021Sminshall break; 54317922Sralph default: 54411758Ssam *nfrontp++ = c; 54517922Sralph break; 54617922Sralph } 5476000Sroot } 5486000Sroot if ((obits & (1 << s)) && (nfrontp - nbackp) > 0) 5496000Sroot netflush(s); 5506000Sroot if (scc > 0) 5516000Sroot telrcv(); 5526000Sroot if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0) 5536000Sroot ttyflush(tout); 5546000Sroot } 5558378Ssam (void) mode(0); 5566000Sroot } 5576000Sroot 5586000Sroot command(top) 5596000Sroot int top; 5606000Sroot { 5616000Sroot register struct cmd *c; 5626000Sroot int oldmode, wasopen; 5636000Sroot 5646000Sroot oldmode = mode(0); 5656000Sroot if (!top) 5666000Sroot putchar('\n'); 5676000Sroot else 56812989Ssam signal(SIGINT, SIG_DFL); 5696000Sroot for (;;) { 5706000Sroot printf("%s> ", prompt); 57113997Ssam if (gets(line) == 0) { 57225800Slepreau if (feof(stdin)) 57325800Slepreau quit(); 5746000Sroot break; 57513997Ssam } 5766000Sroot if (line[0] == 0) 5776000Sroot break; 5786000Sroot makeargv(); 5796000Sroot c = getcmd(margv[0]); 5806000Sroot if (c == (struct cmd *)-1) { 5816000Sroot printf("?Ambiguous command\n"); 5826000Sroot continue; 5836000Sroot } 5846000Sroot if (c == 0) { 5856000Sroot printf("?Invalid command\n"); 5866000Sroot continue; 5876000Sroot } 5886000Sroot (*c->handler)(margc, margv); 5896000Sroot if (c->handler != help) 5906000Sroot break; 5916000Sroot } 5926000Sroot if (!top) { 5936000Sroot if (!connected) 5946000Sroot longjmp(toplevel, 1); 5958378Ssam (void) mode(oldmode); 5966000Sroot } 5976000Sroot } 5986000Sroot 5996000Sroot /* 6006000Sroot * Telnet receiver states for fsm 6016000Sroot */ 6026000Sroot #define TS_DATA 0 6036000Sroot #define TS_IAC 1 6046000Sroot #define TS_WILL 2 6056000Sroot #define TS_WONT 3 6066000Sroot #define TS_DO 4 6076000Sroot #define TS_DONT 5 608*27021Sminshall #define TS_CR 6 6096000Sroot 6106000Sroot telrcv() 6116000Sroot { 6126000Sroot register int c; 6136000Sroot static int state = TS_DATA; 6146000Sroot 6156000Sroot while (scc > 0) { 6166000Sroot c = *sbp++ & 0377, scc--; 6176000Sroot switch (state) { 6186000Sroot 619*27021Sminshall case TS_CR: 620*27021Sminshall state = TS_DATA; 621*27021Sminshall if ((c == '\0') || (c == '\n')) { 622*27021Sminshall break; /* by now, we ignore \n */ 623*27021Sminshall } 624*27021Sminshall 6256000Sroot case TS_DATA: 6269972Ssam if (c == IAC) { 6276000Sroot state = TS_IAC; 6289972Ssam continue; 6299972Ssam } 630*27021Sminshall if (c == '\r') { 631*27021Sminshall if (scc > 0) { 632*27021Sminshall c = *sbp&0377; 633*27021Sminshall if (c == 0) { 634*27021Sminshall sbp++, scc--; 635*27021Sminshall *tfrontp++ = '\r'; 636*27021Sminshall /* 637*27021Sminshall * The following hack is needed since we can't 638*27021Sminshall * set CRMOD on output only. Machines like 639*27021Sminshall * MULTICS like to send \r without \n; since 640*27021Sminshall * we must turn off CRMOD to get proper input, 641*27021Sminshall * the mapping is done here (sigh). 642*27021Sminshall */ 643*27021Sminshall if (crmod) { 644*27021Sminshall *tfrontp++ = '\n'; 645*27021Sminshall } 646*27021Sminshall } else if (!hisopts[TELOPT_ECHO] && 647*27021Sminshall (c == '\n')) { 648*27021Sminshall sbp++, scc--; 649*27021Sminshall *tfrontp++ = '\n'; 650*27021Sminshall } else { 651*27021Sminshall *tfrontp++ = '\r'; 652*27021Sminshall } 653*27021Sminshall } else { 654*27021Sminshall state = TS_CR; 655*27021Sminshall *tfrontp++ = '\r'; 656*27021Sminshall } 657*27021Sminshall } else { 658*27021Sminshall *tfrontp++ = c; 659*27021Sminshall } 6606000Sroot continue; 6616000Sroot 6626000Sroot case TS_IAC: 6636000Sroot switch (c) { 6646000Sroot 6656000Sroot case WILL: 6666000Sroot state = TS_WILL; 6676000Sroot continue; 6686000Sroot 6696000Sroot case WONT: 6706000Sroot state = TS_WONT; 6716000Sroot continue; 6726000Sroot 6736000Sroot case DO: 6746000Sroot state = TS_DO; 6756000Sroot continue; 6766000Sroot 6776000Sroot case DONT: 6786000Sroot state = TS_DONT; 6796000Sroot continue; 6806000Sroot 6816000Sroot case DM: 6826000Sroot ioctl(fileno(stdout), TIOCFLUSH, 0); 6836000Sroot break; 6846000Sroot 6856000Sroot case NOP: 6866000Sroot case GA: 6876000Sroot break; 6886000Sroot 6896000Sroot default: 6906000Sroot break; 6916000Sroot } 6926000Sroot state = TS_DATA; 6936000Sroot continue; 6946000Sroot 6956000Sroot case TS_WILL: 6968345Ssam printoption("RCVD", will, c, !hisopts[c]); 6976000Sroot if (!hisopts[c]) 6986000Sroot willoption(c); 6996000Sroot state = TS_DATA; 7006000Sroot continue; 7016000Sroot 7026000Sroot case TS_WONT: 7038345Ssam printoption("RCVD", wont, c, hisopts[c]); 7046000Sroot if (hisopts[c]) 7056000Sroot wontoption(c); 7066000Sroot state = TS_DATA; 7076000Sroot continue; 7086000Sroot 7096000Sroot case TS_DO: 7108345Ssam printoption("RCVD", doopt, c, !myopts[c]); 7116000Sroot if (!myopts[c]) 7126000Sroot dooption(c); 7136000Sroot state = TS_DATA; 7146000Sroot continue; 7156000Sroot 7166000Sroot case TS_DONT: 7178345Ssam printoption("RCVD", dont, c, myopts[c]); 7186000Sroot if (myopts[c]) { 7196000Sroot myopts[c] = 0; 7206000Sroot sprintf(nfrontp, wont, c); 7218378Ssam nfrontp += sizeof (wont) - 2; 7228345Ssam printoption("SENT", wont, c); 7236000Sroot } 7246000Sroot state = TS_DATA; 7256000Sroot continue; 7266000Sroot } 7276000Sroot } 7286000Sroot } 7296000Sroot 7306000Sroot willoption(option) 7316000Sroot int option; 7326000Sroot { 7336000Sroot char *fmt; 7346000Sroot 7356000Sroot switch (option) { 7366000Sroot 7376000Sroot case TELOPT_ECHO: 7388378Ssam (void) mode(1); 7396000Sroot 7406000Sroot case TELOPT_SGA: 7416000Sroot hisopts[option] = 1; 7426000Sroot fmt = doopt; 7436000Sroot break; 7446000Sroot 7456000Sroot case TELOPT_TM: 7466000Sroot fmt = dont; 7476000Sroot break; 7486000Sroot 7496000Sroot default: 7506000Sroot fmt = dont; 7516000Sroot break; 7526000Sroot } 7536024Ssam sprintf(nfrontp, fmt, option); 7548378Ssam nfrontp += sizeof (dont) - 2; 7558345Ssam printoption("SENT", fmt, option); 7566000Sroot } 7576000Sroot 7586000Sroot wontoption(option) 7596000Sroot int option; 7606000Sroot { 7616000Sroot char *fmt; 7626000Sroot 7636000Sroot switch (option) { 7646000Sroot 7656000Sroot case TELOPT_ECHO: 7668378Ssam (void) mode(2); 7676000Sroot 7686000Sroot case TELOPT_SGA: 7696000Sroot hisopts[option] = 0; 7706000Sroot fmt = dont; 7716000Sroot break; 7726000Sroot 7736000Sroot default: 7746000Sroot fmt = dont; 7756000Sroot } 7766000Sroot sprintf(nfrontp, fmt, option); 7778378Ssam nfrontp += sizeof (doopt) - 2; 7788345Ssam printoption("SENT", fmt, option); 7796000Sroot } 7806000Sroot 7816000Sroot dooption(option) 7826000Sroot int option; 7836000Sroot { 7846000Sroot char *fmt; 7856000Sroot 7866000Sroot switch (option) { 7876000Sroot 7886000Sroot case TELOPT_TM: 7896000Sroot fmt = wont; 7906000Sroot break; 7916000Sroot 79213231Ssam case TELOPT_ECHO: 79313231Ssam (void) mode(2); 79413231Ssam fmt = will; 79513231Ssam hisopts[option] = 0; 79613231Ssam break; 79713231Ssam 7986000Sroot case TELOPT_SGA: 7996000Sroot fmt = will; 8006000Sroot break; 8016000Sroot 8026000Sroot default: 8036000Sroot fmt = wont; 8046000Sroot break; 8056000Sroot } 8066000Sroot sprintf(nfrontp, fmt, option); 8078378Ssam nfrontp += sizeof (doopt) - 2; 8088345Ssam printoption("SENT", fmt, option); 8096000Sroot } 8106000Sroot 8116000Sroot /* 8126000Sroot * Set the escape character. 8136000Sroot */ 8146000Sroot setescape(argc, argv) 8156000Sroot int argc; 8166000Sroot char *argv[]; 8176000Sroot { 8186000Sroot register char *arg; 8196000Sroot char buf[50]; 8206000Sroot 8216000Sroot if (argc > 2) 8226000Sroot arg = argv[1]; 8236000Sroot else { 8246000Sroot printf("new escape character: "); 8256000Sroot gets(buf); 8266000Sroot arg = buf; 8276000Sroot } 8286000Sroot if (arg[0] != '\0') 8296000Sroot escape = arg[0]; 8306000Sroot printf("Escape character is '%s'.\n", control(escape)); 8319972Ssam fflush(stdout); 8326000Sroot } 8336000Sroot 8346024Ssam /*VARARGS*/ 8356024Ssam setoptions() 8366024Ssam { 8379972Ssam 8386024Ssam showoptions = !showoptions; 83925289Skarels printf("%s show option processing.\n", showoptions ? "Will" : "Won't"); 8409972Ssam fflush(stdout); 8416024Ssam } 8426024Ssam 8439972Ssam /*VARARGS*/ 8449972Ssam setcrmod() 8459972Ssam { 8469972Ssam 8479972Ssam crmod = !crmod; 84825289Skarels printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 8499972Ssam fflush(stdout); 8509972Ssam } 8519972Ssam 85210339Ssam /*VARARGS*/ 85310339Ssam setdebug() 85410339Ssam { 85510339Ssam 85617484Sleres debug = debug ? 0 : 1; 85710339Ssam printf("%s turn on socket level debugging.\n", 85825289Skarels debug ? "Will" : "Won't"); 85910339Ssam fflush(stdout); 86017484Sleres if (net > 0 && 86117484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 86211758Ssam perror("setsockopt (SO_DEBUG)"); 86310339Ssam } 86410339Ssam 865*27021Sminshall /*VARARGS*/ 866*27021Sminshall static 867*27021Sminshall setprintnet() 868*27021Sminshall { 869*27021Sminshall 870*27021Sminshall printnet = !printnet; 871*27021Sminshall printf("%s turn on printing of raw network traffic.\n", 872*27021Sminshall printnet ? "Will" : "Wont"); 873*27021Sminshall } 874*27021Sminshall 87517922Sralph sendesc() 87617922Sralph { 87717922Sralph *nfrontp++ = escape; 87817922Sralph } 87917922Sralph 88017922Sralph ayt() 88117922Sralph { 88217922Sralph *nfrontp++ = IAC; 88317922Sralph *nfrontp++ = AYT; 88417922Sralph } 88517922Sralph 88617922Sralph intp() 88717922Sralph { 88817922Sralph *nfrontp++ = IAC; 88917922Sralph *nfrontp++ = IP; 89017922Sralph } 89117922Sralph 8926000Sroot /* 8936000Sroot * Construct a control character sequence 8946000Sroot * for a special character. 8956000Sroot */ 8966000Sroot char * 8976000Sroot control(c) 8986000Sroot register int c; 8996000Sroot { 9006000Sroot static char buf[3]; 9016000Sroot 9026000Sroot if (c == 0177) 9036000Sroot return ("^?"); 9046000Sroot if (c >= 040) { 9056000Sroot buf[0] = c; 9066000Sroot buf[1] = 0; 9076000Sroot } else { 9086000Sroot buf[0] = '^'; 9096000Sroot buf[1] = '@'+c; 9106000Sroot buf[2] = 0; 9116000Sroot } 9126000Sroot return (buf); 9136000Sroot } 9146000Sroot 9156000Sroot struct cmd * 9166000Sroot getcmd(name) 9176000Sroot register char *name; 9186000Sroot { 9196000Sroot register char *p, *q; 9206000Sroot register struct cmd *c, *found; 9216000Sroot register int nmatches, longest; 9226000Sroot 9236000Sroot longest = 0; 9246000Sroot nmatches = 0; 9256000Sroot found = 0; 9266000Sroot for (c = cmdtab; p = c->name; c++) { 9276000Sroot for (q = name; *q == *p++; q++) 9286000Sroot if (*q == 0) /* exact match? */ 9296000Sroot return (c); 9306000Sroot if (!*q) { /* the name was a prefix */ 9316000Sroot if (q - name > longest) { 9326000Sroot longest = q - name; 9336000Sroot nmatches = 1; 9346000Sroot found = c; 9356000Sroot } else if (q - name == longest) 9366000Sroot nmatches++; 9376000Sroot } 9386000Sroot } 9396000Sroot if (nmatches > 1) 9406000Sroot return ((struct cmd *)-1); 9416000Sroot return (found); 9426000Sroot } 9436000Sroot 9446000Sroot deadpeer() 9456000Sroot { 9468378Ssam (void) mode(0); 9476000Sroot longjmp(peerdied, -1); 9486000Sroot } 9496000Sroot 9506000Sroot intr() 9516000Sroot { 9528378Ssam (void) mode(0); 9536000Sroot longjmp(toplevel, -1); 9546000Sroot } 9556000Sroot 9566000Sroot ttyflush(fd) 9576000Sroot { 9586000Sroot int n; 9596000Sroot 9606000Sroot if ((n = tfrontp - tbackp) > 0) 9616000Sroot n = write(fd, tbackp, n); 9628345Ssam if (n < 0) 9638345Ssam return; 9646000Sroot tbackp += n; 9656000Sroot if (tbackp == tfrontp) 9666000Sroot tbackp = tfrontp = ttyobuf; 9676000Sroot } 9686000Sroot 9696000Sroot netflush(fd) 9706000Sroot { 9716000Sroot int n; 9726000Sroot 9736000Sroot if ((n = nfrontp - nbackp) > 0) 9746000Sroot n = write(fd, nbackp, n); 9756501Ssam if (n < 0) { 9766501Ssam if (errno != ENOBUFS && errno != EWOULDBLOCK) { 9778378Ssam (void) mode(0); 9788377Ssam perror(hostname); 9796501Ssam close(fd); 9806501Ssam longjmp(peerdied, -1); 9816501Ssam /*NOTREACHED*/ 9826501Ssam } 9836000Sroot n = 0; 9846501Ssam } 985*27021Sminshall if (printnet) { 986*27021Sminshall Dump('>', nbackp, n); 987*27021Sminshall } 9886000Sroot nbackp += n; 9896000Sroot if (nbackp == nfrontp) 9906000Sroot nbackp = nfrontp = netobuf; 9916000Sroot } 9926024Ssam 993*27021Sminshall static 994*27021Sminshall Dump(direction, buffer, length) 995*27021Sminshall char direction; 996*27021Sminshall char *buffer; 997*27021Sminshall int length; 998*27021Sminshall { 999*27021Sminshall # define BYTES_PER_LINE 32 1000*27021Sminshall # define min(x,y) ((x<y)? x:y) 1001*27021Sminshall char *pThis; 1002*27021Sminshall int offset; 1003*27021Sminshall 1004*27021Sminshall offset = 0; 1005*27021Sminshall 1006*27021Sminshall while (length) { 1007*27021Sminshall /* print one line */ 1008*27021Sminshall fprintf(NetTrace, "%c 0x%x\t", direction, offset); 1009*27021Sminshall pThis = buffer; 1010*27021Sminshall buffer = buffer+min(length, BYTES_PER_LINE); 1011*27021Sminshall while (pThis < buffer) { 1012*27021Sminshall fprintf(NetTrace, "%.2x", (*pThis)&0xff); 1013*27021Sminshall pThis++; 1014*27021Sminshall } 1015*27021Sminshall fprintf(NetTrace, "\n"); 1016*27021Sminshall length -= BYTES_PER_LINE; 1017*27021Sminshall offset += BYTES_PER_LINE; 1018*27021Sminshall if (length < 0) { 1019*27021Sminshall return; 1020*27021Sminshall } 1021*27021Sminshall /* find next unique line */ 1022*27021Sminshall } 1023*27021Sminshall } 1024*27021Sminshall 1025*27021Sminshall 10266293Sroot /*VARARGS*/ 10276293Sroot printoption(direction, fmt, option, what) 10286024Ssam char *direction, *fmt; 10296293Sroot int option, what; 10306024Ssam { 10318345Ssam if (!showoptions) 10328345Ssam return; 10336024Ssam printf("%s ", direction); 10346024Ssam if (fmt == doopt) 10356024Ssam fmt = "do"; 10366024Ssam else if (fmt == dont) 10376024Ssam fmt = "dont"; 10386024Ssam else if (fmt == will) 10396024Ssam fmt = "will"; 10406024Ssam else if (fmt == wont) 10416024Ssam fmt = "wont"; 10426024Ssam else 10436024Ssam fmt = "???"; 10446024Ssam if (option < TELOPT_SUPDUP) 10456293Sroot printf("%s %s", fmt, telopts[option]); 10466024Ssam else 10476293Sroot printf("%s %d", fmt, option); 10486293Sroot if (*direction == '<') { 10496293Sroot printf("\r\n"); 10506293Sroot return; 10516293Sroot } 10526293Sroot printf(" (%s)\r\n", what ? "reply" : "don't reply"); 10536024Ssam } 1054