+
+static void
+suboption()
+{
+ printsub("<", subbuffer, subend-subbuffer+1);
+ switch (subbuffer[0]&0xff) {
+ case TELOPT_TTYPE:
+ if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
+ ;
+ } else {
+ char *name;
+ char namebuf[41];
+ extern char *getenv();
+ int len;
+
+#if defined(TN3270)
+ if (tn3270_ttype()) {
+ return;
+ }
+#endif /* defined(TN3270) */
+ name = getenv("TERM");
+ if ((name == 0) || ((len = strlen(name)) > 40)) {
+ name = "UNKNOWN";
+ len = strlen(name);
+ }
+ if ((len + 4+2) < NETROOM()) {
+ strcpy(namebuf, name);
+ upcase(namebuf);
+ printring(&netoring, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
+ TELQUAL_IS, namebuf, IAC, SE);
+ /* XXX */
+ /* printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); */
+ } else {
+ ExitString("No room in buffer for terminal type.\n",
+ 1);
+ /*NOTREACHED*/
+ }
+ }
+
+ default:
+ break;
+ }
+}
+\f
+
+int
+telrcv()
+{
+ register int c;
+ register int scc;
+ register char *sbp;
+ int count;
+ int returnValue = 0;
+
+ scc = 0;
+ count = 0;
+ while (TTYROOM() > 2) {
+ if (scc == 0) {
+ if (count) {
+ ring_consumed(&netiring, count);
+ returnValue = 1;
+ count = 0;
+ }
+ sbp = netiring.consume;
+ scc = ring_full_consecutive(&netiring);
+ if (scc == 0) {
+ /* No more data coming in */
+ break;
+ }
+ }
+
+ c = *sbp++ & 0xff, scc--; count++;
+
+ switch (telrcv_state) {
+
+ case TS_CR:
+ telrcv_state = TS_DATA;
+ if (c == '\0') {
+ break; /* Ignore \0 after CR */
+ } else if ((c == '\n') && (!hisopts[TELOPT_ECHO]) && !crmod) {
+ TTYADD(c);
+ break;
+ }
+ /* Else, fall through */
+
+ case TS_DATA:
+ if (c == IAC) {
+ telrcv_state = TS_IAC;
+ break;
+ }
+# if defined(TN3270)
+ if (In3270) {
+ *Ifrontp++ = c;
+ while (scc > 0) {
+ c = *sbp++ & 0377, scc--; count++;
+ if (c == IAC) {
+ telrcv_state = TS_IAC;
+ break;
+ }
+ *Ifrontp++ = c;
+ }
+ } else
+# endif /* defined(TN3270) */
+ /*
+ * The 'crmod' hack (see following) is needed
+ * since we can't * set CRMOD on output only.
+ * Machines like MULTICS like to send \r without
+ * \n; since we must turn off CRMOD to get proper
+ * input, the mapping is done here (sigh).
+ */
+ if ((c == '\r') && !hisopts[TELOPT_BINARY]) {
+ if (scc > 0) {
+ c = *sbp&0xff;
+ if (c == 0) {
+ sbp++, scc--; count++;
+ /* a "true" CR */
+ TTYADD('\r');
+ } else if (!hisopts[TELOPT_ECHO] &&
+ (c == '\n')) {
+ sbp++, scc--; count++;
+ TTYADD('\n');
+ } else {
+ TTYADD('\r');
+ if (crmod) {
+ TTYADD('\n');
+ }
+ }
+ } else {
+ telrcv_state = TS_CR;
+ TTYADD('\r');
+ if (crmod) {
+ TTYADD('\n');
+ }
+ }
+ } else {
+ TTYADD(c);
+ }
+ continue;
+
+ case TS_IAC:
+ switch (c) {
+
+ case WILL:
+ telrcv_state = TS_WILL;
+ continue;
+
+ case WONT:
+ telrcv_state = TS_WONT;
+ continue;
+
+ case DO:
+ telrcv_state = TS_DO;
+ continue;
+
+ case DONT:
+ telrcv_state = TS_DONT;
+ continue;
+
+ case DM:
+ /*
+ * We may have missed an urgent notification,
+ * so make sure we flush whatever is in the
+ * buffer currently.
+ */
+ SYNCHing = 1;
+ ttyflush(1);
+ SYNCHing = stilloob();
+ settimer(gotDM);
+ break;
+
+ case NOP:
+ case GA:
+ break;
+
+ case SB:
+ SB_CLEAR();
+ telrcv_state = TS_SB;
+ continue;
+
+# if defined(TN3270)
+ case EOR:
+ if (In3270) {
+ Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
+ if (Ibackp == Ifrontp) {
+ Ibackp = Ifrontp = Ibuf;
+ ISend = 0; /* should have been! */
+ } else {
+ ISend = 1;
+ }
+ }
+ break;
+# endif /* defined(TN3270) */
+
+ case IAC:
+# if !defined(TN3270)
+ TTYADD(IAC);
+# else /* !defined(TN3270) */
+ if (In3270) {
+ *Ifrontp++ = IAC;
+ } else {
+ TTYADD(IAC);
+ }
+# endif /* !defined(TN3270) */
+ break;
+
+ default:
+ break;
+ }
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_WILL:
+ printoption(">RCVD", will, c, !hisopts[c]);
+ if (c == TELOPT_TM) {
+ if (flushout) {
+ flushout = 0;
+ }
+ } else if (!hisopts[c]) {
+ willoption(c, 1);
+ }
+ SetIn3270();
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_WONT:
+ printoption(">RCVD", wont, c, hisopts[c]);
+ if (c == TELOPT_TM) {
+ if (flushout) {
+ flushout = 0;
+ }
+ } else if (hisopts[c]) {
+ wontoption(c, 1);
+ }
+ SetIn3270();
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_DO:
+ printoption(">RCVD", doopt, c, !myopts[c]);
+ if (!myopts[c])
+ dooption(c);
+ SetIn3270();
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_DONT:
+ printoption(">RCVD", dont, c, myopts[c]);
+ if (myopts[c]) {
+ myopts[c] = 0;
+ printring(&netoring, wont, c);
+ flushline = 1;
+ setconnmode(); /* set new tty mode (maybe) */
+ printoption(">SENT", wont, c, 0);
+ }
+ SetIn3270();
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_SB:
+ if (c == IAC) {
+ telrcv_state = TS_SE;
+ } else {
+ SB_ACCUM(c);
+ }
+ continue;
+
+ case TS_SE:
+ if (c != SE) {
+ if (c != IAC) {
+ SB_ACCUM(IAC);
+ }
+ SB_ACCUM(c);
+ telrcv_state = TS_SB;
+ } else {
+ SB_TERM();
+ suboption(); /* handle sub-option */
+ SetIn3270();
+ telrcv_state = TS_DATA;
+ }
+ }
+ }
+ if (count)
+ ring_consumed(&netiring, count);
+ return returnValue||count;
+}
+
+static int
+telsnd()