+ else if (c == '\r') {
+ cstart = i + 1;
+ G.telstate = TS_CR;
+ }
+ /* No IACs were seen so far, no need to copy
+ * bytes within G.buf: */
+ continue;
+ }
+
+ switch (G.telstate) {
+ case TS_CR:
+ /* Prev char was CR. If cur one is NUL, ignore it.
+ * See RFC 1123 section 3.3.1 for discussion of telnet EOL handling.
+ */
+ G.telstate = TS_COPY;
+ if (c == '\0')
+ break;
+ /* else: fall through - need to handle CR IAC ... properly */
+
+ case TS_COPY: /* Prev char was ordinary */
+ /* Similar to NORMAL, but in TS_COPY we need to copy bytes */
+ if (c == IAC)
+ G.telstate = TS_IAC;
+ else
+ G.buf[cstart++] = c;
+ if (c == '\r')
+ G.telstate = TS_CR;
+ break;
+
+ case TS_IAC: /* Prev char was IAC */
+ if (c == IAC) { /* IAC IAC -> one IAC */
+ G.buf[cstart++] = c;
+ G.telstate = TS_COPY;
+ break;
+ }
+ /* else */
+ switch (c) {
+ case SB:
+ G.telstate = TS_SUB1;
+ break;
+ case DO:
+ case DONT:
+ case WILL:
+ case WONT:
+ G.telwish = c;
+ G.telstate = TS_OPT;
+ break;
+ /* DATA MARK must be added later */
+ default:
+ G.telstate = TS_COPY;
+ }
+ break;
+
+ case TS_OPT: /* Prev chars were IAC WILL/WONT/DO/DONT */
+ telopt(c);
+ G.telstate = TS_COPY;
+ break;
+
+ case TS_SUB1: /* Subnegotiation */
+ case TS_SUB2: /* Subnegotiation */
+ subneg(c); /* can change G.telstate */
+ break;