1*21580Sdist /* 2*21580Sdist * Copyright (c) 1983 Regents of the University of California. 3*21580Sdist * All rights reserved. The Berkeley software License Agreement 4*21580Sdist * specifies the terms and conditions for redistribution. 5*21580Sdist */ 6*21580Sdist 711758Ssam #ifndef lint 8*21580Sdist char copyright[] = 9*21580Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10*21580Sdist All rights reserved.\n"; 11*21580Sdist #endif not lint 1211758Ssam 13*21580Sdist #ifndef lint 14*21580Sdist static char sccsid[] = "@(#)telnet.c 5.1 (Berkeley) 05/31/85"; 15*21580Sdist #endif not lint 16*21580Sdist 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; 556000Sroot char *prompt; 569972Ssam char escape = CTRL(]); 576000Sroot 586000Sroot char line[200]; 596000Sroot int margc; 606000Sroot char *margv[20]; 616000Sroot 626000Sroot jmp_buf toplevel; 636000Sroot jmp_buf peerdied; 646000Sroot 656000Sroot extern int errno; 666000Sroot 676000Sroot int tn(), quit(), suspend(), bye(), help(); 686024Ssam int setescape(), status(), toggle(), setoptions(); 6917922Sralph int setcrmod(), setdebug(), sendesc(), ayt(), intp(); 706000Sroot 718378Ssam #define HELPINDENT (sizeof ("connect")) 726000Sroot 736000Sroot struct cmd { 7411758Ssam char *name; /* command name */ 7511758Ssam char *help; /* help string */ 7611758Ssam int (*handler)(); /* routine which executes command */ 776000Sroot }; 786000Sroot 7911758Ssam char openhelp[] = "connect to a site"; 8011758Ssam char closehelp[] = "close current connection"; 8111758Ssam char quithelp[] = "exit telnet"; 8211758Ssam char zhelp[] = "suspend telnet"; 8311758Ssam char debughelp[] = "toggle debugging"; 8411758Ssam char escapehelp[] = "set escape character"; 8511758Ssam char statushelp[] = "print status information"; 8611758Ssam char helphelp[] = "print help information"; 8711758Ssam char optionshelp[] = "toggle viewing of options processing"; 8811758Ssam char crmodhelp[] = "toggle mapping of received carriage returns"; 8917922Sralph char sendeschelp[] = "send escape character"; 9017922Sralph char aythelp[] = "send Are You There"; 9117922Sralph char intphelp[] = "send Interrupt Process"; 926000Sroot 936000Sroot struct cmd cmdtab[] = { 9411758Ssam { "open", openhelp, tn }, 9511758Ssam { "close", closehelp, bye }, 9611758Ssam { "quit", quithelp, quit }, 976000Sroot { "z", zhelp, suspend }, 9811758Ssam { "escape", escapehelp, setescape }, 9911758Ssam { "status", statushelp, status }, 10011758Ssam { "options", optionshelp, setoptions }, 10111758Ssam { "crmod", crmodhelp, setcrmod }, 10211758Ssam { "debug", debughelp, setdebug }, 10317922Sralph { "ayt", aythelp, ayt }, 10417922Sralph { "interrupt", intphelp, intp }, 10517922Sralph { "passthru", sendeschelp, sendesc }, 10611758Ssam { "?", helphelp, help }, 1076000Sroot 0 1086000Sroot }; 1096000Sroot 1109972Ssam struct sockaddr_in sin; 1116000Sroot 1126000Sroot int intr(), deadpeer(); 1136000Sroot char *control(); 1146000Sroot struct cmd *getcmd(); 1158345Ssam struct servent *sp; 1166000Sroot 11713076Ssam struct tchars otc; 11813076Ssam struct ltchars oltc; 11913076Ssam struct sgttyb ottyb; 1208378Ssam 1216000Sroot main(argc, argv) 1226000Sroot int argc; 1236000Sroot char *argv[]; 1246000Sroot { 1258345Ssam sp = getservbyname("telnet", "tcp"); 1268345Ssam if (sp == 0) { 1278345Ssam fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 1288345Ssam exit(1); 1298345Ssam } 13013076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 13113076Ssam ioctl(0, TIOCGETC, (char *)&otc); 13213076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 1336000Sroot setbuf(stdin, 0); 1346000Sroot setbuf(stdout, 0); 1356000Sroot prompt = argv[0]; 13617484Sleres if (argc > 1 && !strcmp(argv[1], "-d")) { 13717484Sleres debug = 1; 13817484Sleres argv++; 13917484Sleres argc--; 14017484Sleres } 1416000Sroot if (argc != 1) { 1426000Sroot if (setjmp(toplevel) != 0) 1436000Sroot exit(0); 1446000Sroot tn(argc, argv); 1456000Sroot } 1466000Sroot setjmp(toplevel); 1476000Sroot for (;;) 1486000Sroot command(1); 1496000Sroot } 1506000Sroot 1518377Ssam char *hostname; 1528377Ssam char hnamebuf[32]; 1536000Sroot 1546000Sroot tn(argc, argv) 1556000Sroot int argc; 1566000Sroot char *argv[]; 1576000Sroot { 1586000Sroot register int c; 1598377Ssam register struct hostent *host; 1606000Sroot 1616000Sroot if (connected) { 1628377Ssam printf("?Already connected to %s\n", hostname); 1636000Sroot return; 1646000Sroot } 1656000Sroot if (argc < 2) { 1666000Sroot strcpy(line, "Connect "); 1676000Sroot printf("(to) "); 1686000Sroot gets(&line[strlen(line)]); 1696000Sroot makeargv(); 1706000Sroot argc = margc; 1716000Sroot argv = margv; 1726000Sroot } 1736000Sroot if (argc > 3) { 1746000Sroot printf("usage: %s host-name [port]\n", argv[0]); 1756000Sroot return; 1766000Sroot } 1778345Ssam host = gethostbyname(argv[1]); 1788377Ssam if (host) { 1799217Ssam sin.sin_family = host->h_addrtype; 1809217Ssam bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length); 1818377Ssam hostname = host->h_name; 1828377Ssam } else { 1839217Ssam sin.sin_family = AF_INET; 1848377Ssam sin.sin_addr.s_addr = inet_addr(argv[1]); 1858377Ssam if (sin.sin_addr.s_addr == -1) { 1868377Ssam printf("%s: unknown host\n", argv[1]); 1878377Ssam return; 1888377Ssam } 1898377Ssam strcpy(hnamebuf, argv[1]); 1908377Ssam hostname = hnamebuf; 1916000Sroot } 1928345Ssam sin.sin_port = sp->s_port; 1936024Ssam if (argc == 3) { 1946024Ssam sin.sin_port = atoi(argv[2]); 1956024Ssam if (sin.sin_port < 0) { 1966024Ssam printf("%s: bad port number\n", argv[2]); 1976024Ssam return; 1986024Ssam } 1999968Ssam sin.sin_port = htons(sin.sin_port); 2006024Ssam } 20117922Sralph net = socket(AF_INET, SOCK_STREAM, 0); 2029217Ssam if (net < 0) { 2039217Ssam perror("telnet: socket"); 2046000Sroot return; 2056000Sroot } 20617484Sleres if (debug && 20717484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 20811758Ssam perror("setsockopt (SO_DEBUG)"); 20912989Ssam signal(SIGINT, intr); 21012989Ssam signal(SIGPIPE, deadpeer); 2116000Sroot printf("Trying...\n"); 21217922Sralph if (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) { 2139217Ssam perror("telnet: connect"); 21412989Ssam signal(SIGINT, SIG_DFL); 2156000Sroot return; 2166000Sroot } 2176000Sroot connected++; 2186000Sroot call(status, "status", 0); 2196000Sroot if (setjmp(peerdied) == 0) 2206000Sroot telnet(net); 2216000Sroot fprintf(stderr, "Connection closed by foreign host.\n"); 2226000Sroot exit(1); 2236000Sroot } 2246000Sroot 2256000Sroot /* 2266000Sroot * Print status about the connection. 2276000Sroot */ 2286000Sroot /*VARARGS*/ 2296000Sroot status() 2306000Sroot { 2316000Sroot if (connected) 2328377Ssam printf("Connected to %s.\n", hostname); 2336000Sroot else 2346000Sroot printf("No connection.\n"); 2356000Sroot printf("Escape character is '%s'.\n", control(escape)); 2369972Ssam fflush(stdout); 2376000Sroot } 2386000Sroot 2396000Sroot makeargv() 2406000Sroot { 2416000Sroot register char *cp; 2426000Sroot register char **argp = margv; 2436000Sroot 2446000Sroot margc = 0; 2456000Sroot for (cp = line; *cp;) { 2466000Sroot while (isspace(*cp)) 2476000Sroot cp++; 2486000Sroot if (*cp == '\0') 2496000Sroot break; 2506000Sroot *argp++ = cp; 2516000Sroot margc += 1; 2526000Sroot while (*cp != '\0' && !isspace(*cp)) 2536000Sroot cp++; 2546000Sroot if (*cp == '\0') 2556000Sroot break; 2566000Sroot *cp++ = '\0'; 2576000Sroot } 2586000Sroot *argp++ = 0; 2596000Sroot } 2606000Sroot 2616000Sroot /*VARARGS*/ 2626000Sroot suspend() 2636000Sroot { 2646000Sroot register int save; 2656000Sroot 2666000Sroot save = mode(0); 2678378Ssam kill(0, SIGTSTP); 2688378Ssam /* reget parameters in case they were changed */ 26913076Ssam ioctl(0, TIOCGETP, (char *)&ottyb); 27013076Ssam ioctl(0, TIOCGETC, (char *)&otc); 27113076Ssam ioctl(0, TIOCGLTC, (char *)&oltc); 2728378Ssam (void) mode(save); 2736000Sroot } 2746000Sroot 2756000Sroot /*VARARGS*/ 2766000Sroot bye() 2776000Sroot { 2788378Ssam register char *op; 2796000Sroot 2808378Ssam (void) mode(0); 2816000Sroot if (connected) { 28211758Ssam shutdown(net, 2); 2836000Sroot printf("Connection closed.\n"); 2846000Sroot close(net); 2856000Sroot connected = 0; 2868378Ssam /* reset his options */ 2878378Ssam for (op = hisopts; op < &hisopts[256]; op++) 2888378Ssam *op = 0; 2896000Sroot } 2906000Sroot } 2916000Sroot 2926000Sroot /*VARARGS*/ 2936000Sroot quit() 2946000Sroot { 2956000Sroot call(bye, "bye", 0); 2966000Sroot exit(0); 2976000Sroot } 2986000Sroot 2996000Sroot /* 3006000Sroot * Help command. 3016000Sroot */ 3026000Sroot help(argc, argv) 3036000Sroot int argc; 3046000Sroot char *argv[]; 3056000Sroot { 3066000Sroot register struct cmd *c; 3076000Sroot 3086000Sroot if (argc == 1) { 3096000Sroot printf("Commands may be abbreviated. Commands are:\n\n"); 3106000Sroot for (c = cmdtab; c->name; c++) 3116000Sroot printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 3126000Sroot return; 3136000Sroot } 3146000Sroot while (--argc > 0) { 3156000Sroot register char *arg; 3166000Sroot arg = *++argv; 3176000Sroot c = getcmd(arg); 3186000Sroot if (c == (struct cmd *)-1) 3196000Sroot printf("?Ambiguous help command %s\n", arg); 3206000Sroot else if (c == (struct cmd *)0) 3216000Sroot printf("?Invalid help command %s\n", arg); 3226000Sroot else 3236000Sroot printf("%s\n", c->help); 3246000Sroot } 3256000Sroot } 3266000Sroot 3276000Sroot /* 3286000Sroot * Call routine with argc, argv set from args (terminated by 0). 3296000Sroot * VARARGS2 3306000Sroot */ 3316000Sroot call(routine, args) 3326000Sroot int (*routine)(); 3336000Sroot int args; 3346000Sroot { 3356000Sroot register int *argp; 3366000Sroot register int argc; 3376000Sroot 3386000Sroot for (argc = 0, argp = &args; *argp++ != 0; argc++) 3396000Sroot ; 3406000Sroot (*routine)(argc, &args); 3416000Sroot } 3426000Sroot 34313076Ssam struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 34413076Ssam struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 3459972Ssam 3466000Sroot mode(f) 3476000Sroot register int f; 3486000Sroot { 3498378Ssam static int prevmode = 0; 35013076Ssam struct tchars *tc; 35113076Ssam struct ltchars *ltc; 35213076Ssam struct sgttyb sb; 35313076Ssam int onoff, old; 3546000Sroot 3558378Ssam if (prevmode == f) 3568378Ssam return (f); 3578378Ssam old = prevmode; 3588378Ssam prevmode = f; 35913076Ssam sb = ottyb; 3606000Sroot switch (f) { 3618378Ssam 3626000Sroot case 0: 3636000Sroot onoff = 0; 3649972Ssam tc = &otc; 36513076Ssam ltc = &oltc; 3666000Sroot break; 3676000Sroot 3686000Sroot case 1: 3696000Sroot case 2: 37013076Ssam sb.sg_flags |= CBREAK; 3718378Ssam if (f == 1) 37213076Ssam sb.sg_flags &= ~(ECHO|CRMOD); 3738378Ssam else 37413076Ssam sb.sg_flags |= ECHO|CRMOD; 37513076Ssam sb.sg_erase = sb.sg_kill = -1; 3769972Ssam tc = ¬c; 37713076Ssam ltc = &noltc; 3786000Sroot onoff = 1; 3799972Ssam break; 3809972Ssam 3819972Ssam default: 3829972Ssam return; 3836000Sroot } 38413076Ssam ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); 38513076Ssam ioctl(fileno(stdin), TIOCSETC, (char *)tc); 38613076Ssam ioctl(fileno(stdin), TIOCSETP, (char *)&sb); 3876000Sroot ioctl(fileno(stdin), FIONBIO, &onoff); 3886000Sroot ioctl(fileno(stdout), FIONBIO, &onoff); 3896000Sroot return (old); 3906000Sroot } 3916000Sroot 3926000Sroot char sibuf[BUFSIZ], *sbp; 3936000Sroot char tibuf[BUFSIZ], *tbp; 3946000Sroot int scc, tcc; 3956000Sroot 3966000Sroot /* 3976000Sroot * Select from tty and network... 3986000Sroot */ 3996000Sroot telnet(s) 4006000Sroot int s; 4016000Sroot { 4026000Sroot register int c; 4036000Sroot int tin = fileno(stdin), tout = fileno(stdout); 4046000Sroot int on = 1; 4056000Sroot 4068378Ssam (void) mode(2); 4076000Sroot ioctl(s, FIONBIO, &on); 40817922Sralph if (!hisopts[TELOPT_SGA]) 40917922Sralph willoption(TELOPT_SGA); 4106000Sroot for (;;) { 4116000Sroot int ibits = 0, obits = 0; 4126000Sroot 4136000Sroot if (nfrontp - nbackp) 4146000Sroot obits |= (1 << s); 4156000Sroot else 4166000Sroot ibits |= (1 << tin); 4176000Sroot if (tfrontp - tbackp) 4186000Sroot obits |= (1 << tout); 4196000Sroot else 4206000Sroot ibits |= (1 << s); 4216000Sroot if (scc < 0 && tcc < 0) 4226000Sroot break; 4239217Ssam select(16, &ibits, &obits, 0, 0); 4246000Sroot if (ibits == 0 && obits == 0) { 4256000Sroot sleep(5); 4266000Sroot continue; 4276000Sroot } 4286000Sroot 4296000Sroot /* 4306000Sroot * Something to read from the network... 4316000Sroot */ 4326000Sroot if (ibits & (1 << s)) { 4338378Ssam scc = read(s, sibuf, sizeof (sibuf)); 4346000Sroot if (scc < 0 && errno == EWOULDBLOCK) 4356000Sroot scc = 0; 4366000Sroot else { 4376000Sroot if (scc <= 0) 4386000Sroot break; 4396000Sroot sbp = sibuf; 4406000Sroot } 4416000Sroot } 4426000Sroot 4436000Sroot /* 4446000Sroot * Something to read from the tty... 4456000Sroot */ 4466000Sroot if (ibits & (1 << tin)) { 4478378Ssam tcc = read(tin, tibuf, sizeof (tibuf)); 4486000Sroot if (tcc < 0 && errno == EWOULDBLOCK) 4496000Sroot tcc = 0; 4506000Sroot else { 4516000Sroot if (tcc <= 0) 4526000Sroot break; 4536000Sroot tbp = tibuf; 4546000Sroot } 4556000Sroot } 4566000Sroot 4576000Sroot while (tcc > 0) { 4586000Sroot register int c; 4596000Sroot 4606000Sroot if ((&netobuf[BUFSIZ] - nfrontp) < 2) 4616000Sroot break; 4626000Sroot c = *tbp++ & 0377, tcc--; 4636000Sroot if (strip(c) == escape) { 4646000Sroot command(0); 4656000Sroot tcc = 0; 4666000Sroot break; 4676000Sroot } 46817922Sralph switch (c) { 46917922Sralph case '\n': 47017922Sralph if (!hisopts[TELOPT_ECHO]) 47117922Sralph *nfrontp++ = '\r'; 47217922Sralph *nfrontp++ = '\n'; 47317922Sralph break; 47417922Sralph case '\r': 47517922Sralph *nfrontp++ = '\r'; 47617922Sralph if (hisopts[TELOPT_ECHO]) 47717922Sralph *nfrontp++ = '\n'; 47817922Sralph else 47917922Sralph *nfrontp++ = '\0'; 48017922Sralph break; 48117922Sralph case IAC: 48217922Sralph *nfrontp++ = IAC; 48317922Sralph /* fall into ... */ 48417922Sralph default: 48511758Ssam *nfrontp++ = c; 48617922Sralph break; 48717922Sralph } 4886000Sroot } 4896000Sroot if ((obits & (1 << s)) && (nfrontp - nbackp) > 0) 4906000Sroot netflush(s); 4916000Sroot if (scc > 0) 4926000Sroot telrcv(); 4936000Sroot if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0) 4946000Sroot ttyflush(tout); 4956000Sroot } 4968378Ssam (void) mode(0); 4976000Sroot } 4986000Sroot 4996000Sroot command(top) 5006000Sroot int top; 5016000Sroot { 5026000Sroot register struct cmd *c; 5036000Sroot int oldmode, wasopen; 5046000Sroot 5056000Sroot oldmode = mode(0); 5066000Sroot if (!top) 5076000Sroot putchar('\n'); 5086000Sroot else 50912989Ssam signal(SIGINT, SIG_DFL); 5106000Sroot for (;;) { 5116000Sroot printf("%s> ", prompt); 51213997Ssam if (gets(line) == 0) { 51313997Ssam if (feof(stdin)) { 51413997Ssam clearerr(stdin); 51513997Ssam putchar('\n'); 51613997Ssam } 5176000Sroot break; 51813997Ssam } 5196000Sroot if (line[0] == 0) 5206000Sroot break; 5216000Sroot makeargv(); 5226000Sroot c = getcmd(margv[0]); 5236000Sroot if (c == (struct cmd *)-1) { 5246000Sroot printf("?Ambiguous command\n"); 5256000Sroot continue; 5266000Sroot } 5276000Sroot if (c == 0) { 5286000Sroot printf("?Invalid command\n"); 5296000Sroot continue; 5306000Sroot } 5316000Sroot (*c->handler)(margc, margv); 5326000Sroot if (c->handler != help) 5336000Sroot break; 5346000Sroot } 5356000Sroot if (!top) { 5366000Sroot if (!connected) 5376000Sroot longjmp(toplevel, 1); 5388378Ssam (void) mode(oldmode); 5396000Sroot } 5406000Sroot } 5416000Sroot 5426000Sroot /* 5436000Sroot * Telnet receiver states for fsm 5446000Sroot */ 5456000Sroot #define TS_DATA 0 5466000Sroot #define TS_IAC 1 5476000Sroot #define TS_WILL 2 5486000Sroot #define TS_WONT 3 5496000Sroot #define TS_DO 4 5506000Sroot #define TS_DONT 5 5516000Sroot 5526000Sroot telrcv() 5536000Sroot { 5546000Sroot register int c; 5556000Sroot static int state = TS_DATA; 5566000Sroot 5576000Sroot while (scc > 0) { 5586000Sroot c = *sbp++ & 0377, scc--; 5596000Sroot switch (state) { 5606000Sroot 5616000Sroot case TS_DATA: 5629972Ssam if (c == IAC) { 5636000Sroot state = TS_IAC; 5649972Ssam continue; 5659972Ssam } 5669972Ssam *tfrontp++ = c; 5679972Ssam /* 5689972Ssam * This hack is needed since we can't set 5699972Ssam * CRMOD on output only. Machines like MULTICS 5709972Ssam * like to send \r without \n; since we must 5719972Ssam * turn off CRMOD to get proper input, the mapping 5729972Ssam * is done here (sigh). 5739972Ssam */ 5749972Ssam if (c == '\r' && crmod) 5759972Ssam *tfrontp++ = '\n'; 5766000Sroot continue; 5776000Sroot 5786000Sroot case TS_IAC: 5796000Sroot switch (c) { 5806000Sroot 5816000Sroot case WILL: 5826000Sroot state = TS_WILL; 5836000Sroot continue; 5846000Sroot 5856000Sroot case WONT: 5866000Sroot state = TS_WONT; 5876000Sroot continue; 5886000Sroot 5896000Sroot case DO: 5906000Sroot state = TS_DO; 5916000Sroot continue; 5926000Sroot 5936000Sroot case DONT: 5946000Sroot state = TS_DONT; 5956000Sroot continue; 5966000Sroot 5976000Sroot case DM: 5986000Sroot ioctl(fileno(stdout), TIOCFLUSH, 0); 5996000Sroot break; 6006000Sroot 6016000Sroot case NOP: 6026000Sroot case GA: 6036000Sroot break; 6046000Sroot 6056000Sroot default: 6066000Sroot break; 6076000Sroot } 6086000Sroot state = TS_DATA; 6096000Sroot continue; 6106000Sroot 6116000Sroot case TS_WILL: 6128345Ssam printoption("RCVD", will, c, !hisopts[c]); 6136000Sroot if (!hisopts[c]) 6146000Sroot willoption(c); 6156000Sroot state = TS_DATA; 6166000Sroot continue; 6176000Sroot 6186000Sroot case TS_WONT: 6198345Ssam printoption("RCVD", wont, c, hisopts[c]); 6206000Sroot if (hisopts[c]) 6216000Sroot wontoption(c); 6226000Sroot state = TS_DATA; 6236000Sroot continue; 6246000Sroot 6256000Sroot case TS_DO: 6268345Ssam printoption("RCVD", doopt, c, !myopts[c]); 6276000Sroot if (!myopts[c]) 6286000Sroot dooption(c); 6296000Sroot state = TS_DATA; 6306000Sroot continue; 6316000Sroot 6326000Sroot case TS_DONT: 6338345Ssam printoption("RCVD", dont, c, myopts[c]); 6346000Sroot if (myopts[c]) { 6356000Sroot myopts[c] = 0; 6366000Sroot sprintf(nfrontp, wont, c); 6378378Ssam nfrontp += sizeof (wont) - 2; 6388345Ssam printoption("SENT", wont, c); 6396000Sroot } 6406000Sroot state = TS_DATA; 6416000Sroot continue; 6426000Sroot } 6436000Sroot } 6446000Sroot } 6456000Sroot 6466000Sroot willoption(option) 6476000Sroot int option; 6486000Sroot { 6496000Sroot char *fmt; 6506000Sroot 6516000Sroot switch (option) { 6526000Sroot 6536000Sroot case TELOPT_ECHO: 6548378Ssam (void) mode(1); 6556000Sroot 6566000Sroot case TELOPT_SGA: 6576000Sroot hisopts[option] = 1; 6586000Sroot fmt = doopt; 6596000Sroot break; 6606000Sroot 6616000Sroot case TELOPT_TM: 6626000Sroot fmt = dont; 6636000Sroot break; 6646000Sroot 6656000Sroot default: 6666000Sroot fmt = dont; 6676000Sroot break; 6686000Sroot } 6696024Ssam sprintf(nfrontp, fmt, option); 6708378Ssam nfrontp += sizeof (dont) - 2; 6718345Ssam printoption("SENT", fmt, option); 6726000Sroot } 6736000Sroot 6746000Sroot wontoption(option) 6756000Sroot int option; 6766000Sroot { 6776000Sroot char *fmt; 6786000Sroot 6796000Sroot switch (option) { 6806000Sroot 6816000Sroot case TELOPT_ECHO: 6828378Ssam (void) mode(2); 6836000Sroot 6846000Sroot case TELOPT_SGA: 6856000Sroot hisopts[option] = 0; 6866000Sroot fmt = dont; 6876000Sroot break; 6886000Sroot 6896000Sroot default: 6906000Sroot fmt = dont; 6916000Sroot } 6926000Sroot sprintf(nfrontp, fmt, option); 6938378Ssam nfrontp += sizeof (doopt) - 2; 6948345Ssam printoption("SENT", fmt, option); 6956000Sroot } 6966000Sroot 6976000Sroot dooption(option) 6986000Sroot int option; 6996000Sroot { 7006000Sroot char *fmt; 7016000Sroot 7026000Sroot switch (option) { 7036000Sroot 7046000Sroot case TELOPT_TM: 7056000Sroot fmt = wont; 7066000Sroot break; 7076000Sroot 70813231Ssam case TELOPT_ECHO: 70913231Ssam (void) mode(2); 71013231Ssam fmt = will; 71113231Ssam hisopts[option] = 0; 71213231Ssam break; 71313231Ssam 7146000Sroot case TELOPT_SGA: 7156000Sroot fmt = will; 7166000Sroot break; 7176000Sroot 7186000Sroot default: 7196000Sroot fmt = wont; 7206000Sroot break; 7216000Sroot } 7226000Sroot sprintf(nfrontp, fmt, option); 7238378Ssam nfrontp += sizeof (doopt) - 2; 7248345Ssam printoption("SENT", fmt, option); 7256000Sroot } 7266000Sroot 7276000Sroot /* 7286000Sroot * Set the escape character. 7296000Sroot */ 7306000Sroot setescape(argc, argv) 7316000Sroot int argc; 7326000Sroot char *argv[]; 7336000Sroot { 7346000Sroot register char *arg; 7356000Sroot char buf[50]; 7366000Sroot 7376000Sroot if (argc > 2) 7386000Sroot arg = argv[1]; 7396000Sroot else { 7406000Sroot printf("new escape character: "); 7416000Sroot gets(buf); 7426000Sroot arg = buf; 7436000Sroot } 7446000Sroot if (arg[0] != '\0') 7456000Sroot escape = arg[0]; 7466000Sroot printf("Escape character is '%s'.\n", control(escape)); 7479972Ssam fflush(stdout); 7486000Sroot } 7496000Sroot 7506024Ssam /*VARARGS*/ 7516024Ssam setoptions() 7526024Ssam { 7539972Ssam 7546024Ssam showoptions = !showoptions; 7556024Ssam printf("%s show option processing.\n", showoptions ? "Will" : "Wont"); 7569972Ssam fflush(stdout); 7576024Ssam } 7586024Ssam 7599972Ssam /*VARARGS*/ 7609972Ssam setcrmod() 7619972Ssam { 7629972Ssam 7639972Ssam crmod = !crmod; 7649972Ssam printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont"); 7659972Ssam fflush(stdout); 7669972Ssam } 7679972Ssam 76810339Ssam /*VARARGS*/ 76910339Ssam setdebug() 77010339Ssam { 77110339Ssam 77217484Sleres debug = debug ? 0 : 1; 77310339Ssam printf("%s turn on socket level debugging.\n", 77410339Ssam debug ? "Will" : "Wont"); 77510339Ssam fflush(stdout); 77617484Sleres if (net > 0 && 77717484Sleres setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0) 77811758Ssam perror("setsockopt (SO_DEBUG)"); 77910339Ssam } 78010339Ssam 78117922Sralph sendesc() 78217922Sralph { 78317922Sralph *nfrontp++ = escape; 78417922Sralph } 78517922Sralph 78617922Sralph ayt() 78717922Sralph { 78817922Sralph *nfrontp++ = IAC; 78917922Sralph *nfrontp++ = AYT; 79017922Sralph } 79117922Sralph 79217922Sralph intp() 79317922Sralph { 79417922Sralph *nfrontp++ = IAC; 79517922Sralph *nfrontp++ = IP; 79617922Sralph } 79717922Sralph 7986000Sroot /* 7996000Sroot * Construct a control character sequence 8006000Sroot * for a special character. 8016000Sroot */ 8026000Sroot char * 8036000Sroot control(c) 8046000Sroot register int c; 8056000Sroot { 8066000Sroot static char buf[3]; 8076000Sroot 8086000Sroot if (c == 0177) 8096000Sroot return ("^?"); 8106000Sroot if (c >= 040) { 8116000Sroot buf[0] = c; 8126000Sroot buf[1] = 0; 8136000Sroot } else { 8146000Sroot buf[0] = '^'; 8156000Sroot buf[1] = '@'+c; 8166000Sroot buf[2] = 0; 8176000Sroot } 8186000Sroot return (buf); 8196000Sroot } 8206000Sroot 8216000Sroot struct cmd * 8226000Sroot getcmd(name) 8236000Sroot register char *name; 8246000Sroot { 8256000Sroot register char *p, *q; 8266000Sroot register struct cmd *c, *found; 8276000Sroot register int nmatches, longest; 8286000Sroot 8296000Sroot longest = 0; 8306000Sroot nmatches = 0; 8316000Sroot found = 0; 8326000Sroot for (c = cmdtab; p = c->name; c++) { 8336000Sroot for (q = name; *q == *p++; q++) 8346000Sroot if (*q == 0) /* exact match? */ 8356000Sroot return (c); 8366000Sroot if (!*q) { /* the name was a prefix */ 8376000Sroot if (q - name > longest) { 8386000Sroot longest = q - name; 8396000Sroot nmatches = 1; 8406000Sroot found = c; 8416000Sroot } else if (q - name == longest) 8426000Sroot nmatches++; 8436000Sroot } 8446000Sroot } 8456000Sroot if (nmatches > 1) 8466000Sroot return ((struct cmd *)-1); 8476000Sroot return (found); 8486000Sroot } 8496000Sroot 8506000Sroot deadpeer() 8516000Sroot { 8528378Ssam (void) mode(0); 8536000Sroot longjmp(peerdied, -1); 8546000Sroot } 8556000Sroot 8566000Sroot intr() 8576000Sroot { 8588378Ssam (void) mode(0); 8596000Sroot longjmp(toplevel, -1); 8606000Sroot } 8616000Sroot 8626000Sroot ttyflush(fd) 8636000Sroot { 8646000Sroot int n; 8656000Sroot 8666000Sroot if ((n = tfrontp - tbackp) > 0) 8676000Sroot n = write(fd, tbackp, n); 8688345Ssam if (n < 0) 8698345Ssam return; 8706000Sroot tbackp += n; 8716000Sroot if (tbackp == tfrontp) 8726000Sroot tbackp = tfrontp = ttyobuf; 8736000Sroot } 8746000Sroot 8756000Sroot netflush(fd) 8766000Sroot { 8776000Sroot int n; 8786000Sroot 8796000Sroot if ((n = nfrontp - nbackp) > 0) 8806000Sroot n = write(fd, nbackp, n); 8816501Ssam if (n < 0) { 8826501Ssam if (errno != ENOBUFS && errno != EWOULDBLOCK) { 8838378Ssam (void) mode(0); 8848377Ssam perror(hostname); 8856501Ssam close(fd); 8866501Ssam longjmp(peerdied, -1); 8876501Ssam /*NOTREACHED*/ 8886501Ssam } 8896000Sroot n = 0; 8906501Ssam } 8916000Sroot nbackp += n; 8926000Sroot if (nbackp == nfrontp) 8936000Sroot nbackp = nfrontp = netobuf; 8946000Sroot } 8956024Ssam 8966293Sroot /*VARARGS*/ 8976293Sroot printoption(direction, fmt, option, what) 8986024Ssam char *direction, *fmt; 8996293Sroot int option, what; 9006024Ssam { 9018345Ssam if (!showoptions) 9028345Ssam return; 9036024Ssam printf("%s ", direction); 9046024Ssam if (fmt == doopt) 9056024Ssam fmt = "do"; 9066024Ssam else if (fmt == dont) 9076024Ssam fmt = "dont"; 9086024Ssam else if (fmt == will) 9096024Ssam fmt = "will"; 9106024Ssam else if (fmt == wont) 9116024Ssam fmt = "wont"; 9126024Ssam else 9136024Ssam fmt = "???"; 9146024Ssam if (option < TELOPT_SUPDUP) 9156293Sroot printf("%s %s", fmt, telopts[option]); 9166024Ssam else 9176293Sroot printf("%s %d", fmt, option); 9186293Sroot if (*direction == '<') { 9196293Sroot printf("\r\n"); 9206293Sroot return; 9216293Sroot } 9226293Sroot printf(" (%s)\r\n", what ? "reply" : "don't reply"); 9236024Ssam } 924