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*25425Skarels static char sccsid[] = "@(#)telnet.c 5.3 (Berkeley) 11/08/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; 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; 161*25425Skarels 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 } 179*25425Skarels sin.sin_addr.s_addr = inet_addr(argv[1]); 180*25425Skarels if (sin.sin_addr.s_addr != -1) { 181*25425Skarels sin.sin_family = AF_INET; 182*25425Skarels strcpy(hnamebuf, argv[1]); 183*25425Skarels hostname = hnamebuf; 1848377Ssam } else { 185*25425Skarels host = gethostbyname(argv[1]); 186*25425Skarels if (host) { 187*25425Skarels sin.sin_family = host->h_addrtype; 188*25425Skarels bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 189*25425Skarels host->h_length); 190*25425Skarels hostname = host->h_name; 191*25425Skarels } 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"); 224*25425Skarels while (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) { 225*25425Skarels if (host && host->h_addr_list[1]) { 226*25425Skarels int oerrno = errno; 227*25425Skarels 228*25425Skarels fprintf(stderr, "telnet: connect to address %s: ", 229*25425Skarels inet_ntoa(sin.sin_addr)); 230*25425Skarels errno = oerrno; 231*25425Skarels perror(0); 232*25425Skarels host->h_addr_list++; 233*25425Skarels bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, 234*25425Skarels host->h_length); 235*25425Skarels fprintf(stderr, "Trying %s...\n", 236*25425Skarels inet_ntoa(sin.sin_addr)); 237*25425Skarels continue; 238*25425Skarels } 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) { 53913997Ssam if (feof(stdin)) { 54013997Ssam clearerr(stdin); 54113997Ssam putchar('\n'); 54213997Ssam } 5436000Sroot break; 54413997Ssam } 5456000Sroot if (line[0] == 0) 5466000Sroot break; 5476000Sroot makeargv(); 5486000Sroot c = getcmd(margv[0]); 5496000Sroot if (c == (struct cmd *)-1) { 5506000Sroot printf("?Ambiguous command\n"); 5516000Sroot continue; 5526000Sroot } 5536000Sroot if (c == 0) { 5546000Sroot printf("?Invalid command\n"); 5556000Sroot continue; 5566000Sroot } 5576000Sroot (*c->handler)(margc, margv); 5586000Sroot if (c->handler != help) 5596000Sroot break; 5606000Sroot } 5616000Sroot if (!top) { 5626000Sroot if (!connected) 5636000Sroot longjmp(toplevel, 1); 5648378Ssam (void) mode(oldmode); 5656000Sroot } 5666000Sroot } 5676000Sroot 5686000Sroot /* 5696000Sroot * Telnet receiver states for fsm 5706000Sroot */ 5716000Sroot #define TS_DATA 0 5726000Sroot #define TS_IAC 1 5736000Sroot #define TS_WILL 2 5746000Sroot #define TS_WONT 3 5756000Sroot #define TS_DO 4 5766000Sroot #define TS_DONT 5 5776000Sroot 5786000Sroot telrcv() 5796000Sroot { 5806000Sroot register int c; 5816000Sroot static int state = TS_DATA; 5826000Sroot 5836000Sroot while (scc > 0) { 5846000Sroot c = *sbp++ & 0377, scc--; 5856000Sroot switch (state) { 5866000Sroot 5876000Sroot case TS_DATA: 5889972Ssam if (c == IAC) { 5896000Sroot state = TS_IAC; 5909972Ssam continue; 5919972Ssam } 5929972Ssam *tfrontp++ = c; 5939972Ssam /* 5949972Ssam * This hack is needed since we can't set 5959972Ssam * CRMOD on output only. Machines like MULTICS 5969972Ssam * like to send \r without \n; since we must 5979972Ssam * turn off CRMOD to get proper input, the mapping 5989972Ssam * is done here (sigh). 5999972Ssam */ 6009972Ssam if (c == '\r' && crmod) 6019972Ssam *tfrontp++ = '\n'; 6026000Sroot continue; 6036000Sroot 6046000Sroot case TS_IAC: 6056000Sroot switch (c) { 6066000Sroot 6076000Sroot case WILL: 6086000Sroot state = TS_WILL; 6096000Sroot continue; 6106000Sroot 6116000Sroot case WONT: 6126000Sroot state = TS_WONT; 6136000Sroot continue; 6146000Sroot 6156000Sroot case DO: 6166000Sroot state = TS_DO; 6176000Sroot continue; 6186000Sroot 6196000Sroot case DONT: 6206000Sroot state = TS_DONT; 6216000Sroot continue; 6226000Sroot 6236000Sroot case DM: 6246000Sroot ioctl(fileno(stdout), TIOCFLUSH, 0); 6256000Sroot break; 6266000Sroot 6276000Sroot case NOP: 6286000Sroot case GA: 6296000Sroot break; 6306000Sroot 6316000Sroot default: 6326000Sroot break; 6336000Sroot } 6346000Sroot state = TS_DATA; 6356000Sroot continue; 6366000Sroot 6376000Sroot case TS_WILL: 6388345Ssam printoption("RCVD", will, c, !hisopts[c]); 6396000Sroot if (!hisopts[c]) 6406000Sroot willoption(c); 6416000Sroot state = TS_DATA; 6426000Sroot continue; 6436000Sroot 6446000Sroot case TS_WONT: 6458345Ssam printoption("RCVD", wont, c, hisopts[c]); 6466000Sroot if (hisopts[c]) 6476000Sroot wontoption(c); 6486000Sroot state = TS_DATA; 6496000Sroot continue; 6506000Sroot 6516000Sroot case TS_DO: 6528345Ssam printoption("RCVD", doopt, c, !myopts[c]); 6536000Sroot if (!myopts[c]) 6546000Sroot dooption(c); 6556000Sroot state = TS_DATA; 6566000Sroot continue; 6576000Sroot 6586000Sroot case TS_DONT: 6598345Ssam printoption("RCVD", dont, c, myopts[c]); 6606000Sroot if (myopts[c]) { 6616000Sroot myopts[c] = 0; 6626000Sroot sprintf(nfrontp, wont, c); 6638378Ssam nfrontp += sizeof (wont) - 2; 6648345Ssam printoption("SENT", wont, c); 6656000Sroot } 6666000Sroot state = TS_DATA; 6676000Sroot continue; 6686000Sroot } 6696000Sroot } 6706000Sroot } 6716000Sroot 6726000Sroot willoption(option) 6736000Sroot int option; 6746000Sroot { 6756000Sroot char *fmt; 6766000Sroot 6776000Sroot switch (option) { 6786000Sroot 6796000Sroot case TELOPT_ECHO: 6808378Ssam (void) mode(1); 6816000Sroot 6826000Sroot case TELOPT_SGA: 6836000Sroot hisopts[option] = 1; 6846000Sroot fmt = doopt; 6856000Sroot break; 6866000Sroot 6876000Sroot case TELOPT_TM: 6886000Sroot fmt = dont; 6896000Sroot break; 6906000Sroot 6916000Sroot default: 6926000Sroot fmt = dont; 6936000Sroot break; 6946000Sroot } 6956024Ssam sprintf(nfrontp, fmt, option); 6968378Ssam nfrontp += sizeof (dont) - 2; 6978345Ssam printoption("SENT", fmt, option); 6986000Sroot } 6996000Sroot 7006000Sroot wontoption(option) 7016000Sroot int option; 7026000Sroot { 7036000Sroot char *fmt; 7046000Sroot 7056000Sroot switch (option) { 7066000Sroot 7076000Sroot case TELOPT_ECHO: 7088378Ssam (void) mode(2); 7096000Sroot 7106000Sroot case TELOPT_SGA: 7116000Sroot hisopts[option] = 0; 7126000Sroot fmt = dont; 7136000Sroot break; 7146000Sroot 7156000Sroot default: 7166000Sroot fmt = dont; 7176000Sroot } 7186000Sroot sprintf(nfrontp, fmt, option); 7198378Ssam nfrontp += sizeof (doopt) - 2; 7208345Ssam printoption("SENT", fmt, option); 7216000Sroot } 7226000Sroot 7236000Sroot dooption(option) 7246000Sroot int option; 7256000Sroot { 7266000Sroot char *fmt; 7276000Sroot 7286000Sroot switch (option) { 7296000Sroot 7306000Sroot case TELOPT_TM: 7316000Sroot fmt = wont; 7326000Sroot break; 7336000Sroot 73413231Ssam case TELOPT_ECHO: 73513231Ssam (void) mode(2); 73613231Ssam fmt = will; 73713231Ssam hisopts[option] = 0; 73813231Ssam break; 73913231Ssam 7406000Sroot case TELOPT_SGA: 7416000Sroot fmt = will; 7426000Sroot break; 7436000Sroot 7446000Sroot default: 7456000Sroot fmt = wont; 7466000Sroot break; 7476000Sroot } 7486000Sroot sprintf(nfrontp, fmt, option); 7498378Ssam nfrontp += sizeof (doopt) - 2; 7508345Ssam printoption("SENT", fmt, option); 7516000Sroot } 7526000Sroot 7536000Sroot /* 7546000Sroot * Set the escape character. 7556000Sroot */ 7566000Sroot setescape(argc, argv) 7576000Sroot int argc; 7586000Sroot char *argv[]; 7596000Sroot { 7606000Sroot register char *arg; 7616000Sroot char buf[50]; 7626000Sroot 7636000Sroot if (argc > 2) 7646000Sroot arg = argv[1]; 7656000Sroot else { 7666000Sroot printf("new escape character: "); 7676000Sroot gets(buf); 7686000Sroot arg = buf; 7696000Sroot } 7706000Sroot if (arg[0] != '\0') 7716000Sroot escape = arg[0]; 7726000Sroot printf("Escape character is '%s'.\n", control(escape)); 7739972Ssam fflush(stdout); 7746000Sroot } 7756000Sroot 7766024Ssam /*VARARGS*/ 7776024Ssam setoptions() 7786024Ssam { 7799972Ssam 7806024Ssam showoptions = !showoptions; 78125289Skarels printf("%s show option processing.\n", showoptions ? "Will" : "Won't"); 7829972Ssam fflush(stdout); 7836024Ssam } 7846024Ssam 7859972Ssam /*VARARGS*/ 7869972Ssam setcrmod() 7879972Ssam { 7889972Ssam 7899972Ssam crmod = !crmod; 79025289Skarels printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 7919972Ssam fflush(stdout); 7929972Ssam } 7939972Ssam 79410339Ssam /*VARARGS*/ 79510339Ssam setdebug() 79610339Ssam { 79710339Ssam 79817484Sleres debug = debug ? 0 : 1; 79910339Ssam printf("%s turn on socket level debugging.\n", 80025289Skarels debug ? "Will" : "Won't"); 80110339Ssam fflush(stdout); 80217484Sleres if (net > 0 && 80317484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 80411758Ssam perror("setsockopt (SO_DEBUG)"); 80510339Ssam } 80610339Ssam 80717922Sralph sendesc() 80817922Sralph { 80917922Sralph *nfrontp++ = escape; 81017922Sralph } 81117922Sralph 81217922Sralph ayt() 81317922Sralph { 81417922Sralph *nfrontp++ = IAC; 81517922Sralph *nfrontp++ = AYT; 81617922Sralph } 81717922Sralph 81817922Sralph intp() 81917922Sralph { 82017922Sralph *nfrontp++ = IAC; 82117922Sralph *nfrontp++ = IP; 82217922Sralph } 82317922Sralph 8246000Sroot /* 8256000Sroot * Construct a control character sequence 8266000Sroot * for a special character. 8276000Sroot */ 8286000Sroot char * 8296000Sroot control(c) 8306000Sroot register int c; 8316000Sroot { 8326000Sroot static char buf[3]; 8336000Sroot 8346000Sroot if (c == 0177) 8356000Sroot return ("^?"); 8366000Sroot if (c >= 040) { 8376000Sroot buf[0] = c; 8386000Sroot buf[1] = 0; 8396000Sroot } else { 8406000Sroot buf[0] = '^'; 8416000Sroot buf[1] = '@'+c; 8426000Sroot buf[2] = 0; 8436000Sroot } 8446000Sroot return (buf); 8456000Sroot } 8466000Sroot 8476000Sroot struct cmd * 8486000Sroot getcmd(name) 8496000Sroot register char *name; 8506000Sroot { 8516000Sroot register char *p, *q; 8526000Sroot register struct cmd *c, *found; 8536000Sroot register int nmatches, longest; 8546000Sroot 8556000Sroot longest = 0; 8566000Sroot nmatches = 0; 8576000Sroot found = 0; 8586000Sroot for (c = cmdtab; p = c->name; c++) { 8596000Sroot for (q = name; *q == *p++; q++) 8606000Sroot if (*q == 0) /* exact match? */ 8616000Sroot return (c); 8626000Sroot if (!*q) { /* the name was a prefix */ 8636000Sroot if (q - name > longest) { 8646000Sroot longest = q - name; 8656000Sroot nmatches = 1; 8666000Sroot found = c; 8676000Sroot } else if (q - name == longest) 8686000Sroot nmatches++; 8696000Sroot } 8706000Sroot } 8716000Sroot if (nmatches > 1) 8726000Sroot return ((struct cmd *)-1); 8736000Sroot return (found); 8746000Sroot } 8756000Sroot 8766000Sroot deadpeer() 8776000Sroot { 8788378Ssam (void) mode(0); 8796000Sroot longjmp(peerdied, -1); 8806000Sroot } 8816000Sroot 8826000Sroot intr() 8836000Sroot { 8848378Ssam (void) mode(0); 8856000Sroot longjmp(toplevel, -1); 8866000Sroot } 8876000Sroot 8886000Sroot ttyflush(fd) 8896000Sroot { 8906000Sroot int n; 8916000Sroot 8926000Sroot if ((n = tfrontp - tbackp) > 0) 8936000Sroot n = write(fd, tbackp, n); 8948345Ssam if (n < 0) 8958345Ssam return; 8966000Sroot tbackp += n; 8976000Sroot if (tbackp == tfrontp) 8986000Sroot tbackp = tfrontp = ttyobuf; 8996000Sroot } 9006000Sroot 9016000Sroot netflush(fd) 9026000Sroot { 9036000Sroot int n; 9046000Sroot 9056000Sroot if ((n = nfrontp - nbackp) > 0) 9066000Sroot n = write(fd, nbackp, n); 9076501Ssam if (n < 0) { 9086501Ssam if (errno != ENOBUFS && errno != EWOULDBLOCK) { 9098378Ssam (void) mode(0); 9108377Ssam perror(hostname); 9116501Ssam close(fd); 9126501Ssam longjmp(peerdied, -1); 9136501Ssam /*NOTREACHED*/ 9146501Ssam } 9156000Sroot n = 0; 9166501Ssam } 9176000Sroot nbackp += n; 9186000Sroot if (nbackp == nfrontp) 9196000Sroot nbackp = nfrontp = netobuf; 9206000Sroot } 9216024Ssam 9226293Sroot /*VARARGS*/ 9236293Sroot printoption(direction, fmt, option, what) 9246024Ssam char *direction, *fmt; 9256293Sroot int option, what; 9266024Ssam { 9278345Ssam if (!showoptions) 9288345Ssam return; 9296024Ssam printf("%s ", direction); 9306024Ssam if (fmt == doopt) 9316024Ssam fmt = "do"; 9326024Ssam else if (fmt == dont) 9336024Ssam fmt = "dont"; 9346024Ssam else if (fmt == will) 9356024Ssam fmt = "will"; 9366024Ssam else if (fmt == wont) 9376024Ssam fmt = "wont"; 9386024Ssam else 9396024Ssam fmt = "???"; 9406024Ssam if (option < TELOPT_SUPDUP) 9416293Sroot printf("%s %s", fmt, telopts[option]); 9426024Ssam else 9436293Sroot printf("%s %d", fmt, option); 9446293Sroot if (*direction == '<') { 9456293Sroot printf("\r\n"); 9466293Sroot return; 9476293Sroot } 9486293Sroot printf(" (%s)\r\n", what ? "reply" : "don't reply"); 9496024Ssam } 950