-/*
- * State for recv fsm
- */
-#define TS_DATA 0 /* base state */
-#define TS_IAC 1 /* look for double IAC's */
-#define TS_CR 2 /* CR-LF ->'s CR */
-#define TS_SB 3 /* throw away begin's... */
-#define TS_SE 4 /* ...end's (suboption negotiation) */
-#define TS_WILL 5 /* will option negotiation */
-#define TS_WONT 6 /* wont " */
-#define TS_DO 7 /* do " */
-#define TS_DONT 8 /* dont " */
-
-telrcv()
-{
- register int c;
- static int state = TS_DATA;
-
- while (ncc > 0) {
- if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
- return;
- c = *netip++ & 0377, ncc--;
- switch (state) {
-
- case TS_CR:
- state = TS_DATA;
- if ((c == 0) || (c == '\n')) {
- break;
- }
- /* FALL THROUGH */
-
- case TS_DATA:
- if (c == IAC) {
- state = TS_IAC;
- break;
- }
- if (inter > 0)
- break;
- /*
- * We map \r\n ==> \n, since \r\n says
- * that we want to be in column 1 of the next
- * printable line, and \n is the standard
- * unix way of saying that (\r is only good
- * if CRMOD is set, which it normally is).
- */
- if ((myopts[TELOPT_BINARY] == OPT_NO) && c == '\r') {
- if ((ncc > 0) && ('\n' == *netip)) {
- netip++; ncc--;
- c = '\n';
- } else {
- state = TS_CR;
- }
- }
- *pfrontp++ = c;
- break;
-
- case TS_IAC:
- switch (c) {
-
- /*
- * Send the process on the pty side an
- * interrupt. Do this with a NULL or
- * interrupt char; depending on the tty mode.
- */
- case IP:
- interrupt();
- break;
-
- case BREAK:
- sendbrk();
- break;
-
- /*
- * Are You There?
- */
- case AYT:
- strcpy(nfrontp, "\r\n[Yes]\r\n");
- nfrontp += 9;
- break;
-
- /*
- * Abort Output
- */
- case AO: {
- struct ltchars tmpltc;
-
- ptyflush(); /* half-hearted */
- ioctl(pty, TIOCGLTC, &tmpltc);
- if (tmpltc.t_flushc != '\377') {
- *pfrontp++ = tmpltc.t_flushc;
- }
- netclear(); /* clear buffer back */
- *nfrontp++ = IAC;
- *nfrontp++ = DM;
- neturg = nfrontp-1; /* off by one XXX */
- break;
- }
-
- /*
- * Erase Character and
- * Erase Line
- */
- case EC:
- case EL: {
- struct sgttyb b;
- char ch;
-
- ptyflush(); /* half-hearted */
- ioctl(pty, TIOCGETP, &b);
- ch = (c == EC) ?
- b.sg_erase : b.sg_kill;
- if (ch != '\377') {
- *pfrontp++ = ch;
- }
- break;
- }
-
- /*
- * Check for urgent data...
- */
- case DM:
- SYNCHing = stilloob(net);
- settimer(gotDM);
- break;
-
-
- /*
- * Begin option subnegotiation...
- */
- case SB:
- state = TS_SB;
- continue;
-
- case WILL:
- state = TS_WILL;
- continue;
-
- case WONT:
- state = TS_WONT;
- continue;
-
- case DO:
- state = TS_DO;
- continue;
-
- case DONT:
- state = TS_DONT;
- continue;
-
- case IAC:
- *pfrontp++ = c;
- break;
- }
- state = TS_DATA;
- break;
-
- case TS_SB:
- if (c == IAC) {
- state = TS_SE;
- } else {
- SB_ACCUM(c);
- }
- break;
-
- case TS_SE:
- if (c != SE) {
- if (c != IAC) {
- SB_ACCUM(IAC);
- }
- SB_ACCUM(c);
- state = TS_SB;
- } else {
- SB_TERM();
- suboption(); /* handle sub-option */
- state = TS_DATA;
- }
- break;
-
- case TS_WILL:
- if (hisopts[c] != OPT_YES)
- willoption(c);
- state = TS_DATA;
- continue;
-
- case TS_WONT:
- if (hisopts[c] != OPT_NO)
- wontoption(c);
- state = TS_DATA;
- continue;
-
- case TS_DO:
- if (myopts[c] != OPT_YES)
- dooption(c);
- state = TS_DATA;
- continue;
-
- case TS_DONT:
- if (myopts[c] != OPT_NO) {
- dontoption(c);
- }
- state = TS_DATA;
- continue;
-
- default:
- syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
- printf("telnetd: panic state=%d\n", state);
- exit(1);
- }
- }
-}
-
-willoption(option)
- int option;
-{
- char *fmt;
-
- switch (option) {
-
- case TELOPT_BINARY:
- mode(RAW, 0);
- fmt = doopt;
- break;
-
- case TELOPT_ECHO:
- not42 = 0; /* looks like a 4.2 system */
- /*
- * Now, in a 4.2 system, to break them out of ECHOing
- * (to the terminal) mode, we need to send a "WILL ECHO".
- * Kludge upon kludge!
- */
- if (myopts[TELOPT_ECHO] == OPT_YES) {
- dooption(TELOPT_ECHO);
- }
- fmt = dont;
- break;
-
- case TELOPT_TTYPE:
- settimer(ttypeopt);
- if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) {
- hisopts[TELOPT_TTYPE] = OPT_YES;
- return;
- }
- fmt = doopt;
- break;
-
- case TELOPT_SGA:
- fmt = doopt;
- break;
-
- case TELOPT_TM:
- fmt = dont;
- break;
-
- default:
- fmt = dont;
- break;
- }
- if (fmt == doopt) {
- hisopts[option] = OPT_YES;
- } else {
- hisopts[option] = OPT_NO;
- }
- sprintf(nfrontp, fmt, option);
- nfrontp += sizeof (dont) - 2;
-}
-
-wontoption(option)
- int option;
-{
- char *fmt;
-
- switch (option) {
- case TELOPT_ECHO:
- not42 = 1; /* doesn't seem to be a 4.2 system */
- break;
-
- case TELOPT_BINARY:
- mode(0, RAW);
- break;
-
- case TELOPT_TTYPE:
- settimer(ttypeopt);
- break;
- }
-
- fmt = dont;
- hisopts[option] = OPT_NO;
- sprintf(nfrontp, fmt, option);
- nfrontp += sizeof (doopt) - 2;
-}
-
-dooption(option)
- int option;
-{
- char *fmt;
-
- switch (option) {
-
- case TELOPT_TM:
- fmt = wont;
- break;
-
- case TELOPT_ECHO:
- mode(ECHO|CRMOD, 0);
- fmt = will;
- break;
-
- case TELOPT_BINARY:
- mode(RAW, 0);
- fmt = will;
- break;
-
- case TELOPT_SGA:
- fmt = will;
- break;
-
- default:
- fmt = wont;
- break;
- }
- if (fmt == will) {
- myopts[option] = OPT_YES;
- } else {
- myopts[option] = OPT_NO;
- }
- sprintf(nfrontp, fmt, option);
- nfrontp += sizeof (doopt) - 2;
-}
-
-
-dontoption(option)
-int option;
-{
- char *fmt;
-
- switch (option) {
- case TELOPT_ECHO: /* we should stop echoing */
- mode(0, ECHO|CRMOD);
- fmt = wont;
- break;
-
- default:
- fmt = wont;
- break;
- }
-
- if (fmt = wont) {
- myopts[option] = OPT_NO;
- } else {
- myopts[option] = OPT_YES;
- }
- sprintf(nfrontp, fmt, option);
- nfrontp += sizeof (wont) - 2;
-}
-
-/*
- * suboption()
- *
- * Look at the sub-option buffer, and try to be helpful to the other
- * side.
- *
- * Currently we recognize:
- *
- * Terminal type is
- */
-
-suboption()
-{
- switch (SB_GET()) {
- case TELOPT_TTYPE: { /* Yaaaay! */
- static char terminalname[5+41] = "TERM=";
-
- settimer(ttypesubopt);
-
- if (SB_GET() != TELQUAL_IS) {
- return; /* ??? XXX but, this is the most robust */
- }
-
- terminaltype = terminalname+strlen(terminalname);
-
- while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
- !SB_EOF()) {
- register int c;
-
- c = SB_GET();
- if (isupper(c)) {
- c = tolower(c);
- }
- *terminaltype++ = c; /* accumulate name */
- }
- *terminaltype = 0;
- terminaltype = terminalname;
- break;
- }
-
- default:
- ;
- }
-}
-
-mode(on, off)
- int on, off;
-{
- struct sgttyb b;
-
- ptyflush();
- ioctl(pty, TIOCGETP, &b);
- b.sg_flags |= on;
- b.sg_flags &= ~off;
- ioctl(pty, TIOCSETP, &b);
-}