static void do_telnet_read(Telnet telnet, char *buf, int len) { while (len--) { int c = (unsigned char) *buf++; switch (telnet->state) { case TOP_LEVEL: case SEENCR: if (c == NUL && telnet->state == SEENCR) telnet->state = TOP_LEVEL; else if (c == IAC) telnet->state = SEENIAC; else { if (!telnet->in_synch) c_write1(telnet, c); #if 1 /* I can't get the F***ing winsock to insert the urgent IAC * into the right position! Even with SO_OOBINLINE it gives * it to recv too soon. And of course the DM byte (that * arrives in the same packet!) appears several K later!! * * Oh well, we do get the DM in the right place so I'll * just stop hiding on the next 0xf2 and hope for the best. */ else if (c == DM) telnet->in_synch = 0; #endif if (c == CR && telnet->opt_states[o_they_bin.index] != ACTIVE) telnet->state = SEENCR; else telnet->state = TOP_LEVEL; } break; case SEENIAC: if (c == DO) telnet->state = SEENDO; else if (c == DONT) telnet->state = SEENDONT; else if (c == WILL) telnet->state = SEENWILL; else if (c == WONT) telnet->state = SEENWONT; else if (c == SB) telnet->state = SEENSB; else if (c == DM) { telnet->in_synch = 0; telnet->state = TOP_LEVEL; } else { /* ignore everything else; print it if it's IAC */ if (c == IAC) { c_write1(telnet, c); } telnet->state = TOP_LEVEL; } break; case SEENWILL: proc_rec_opt(telnet, WILL, c); telnet->state = TOP_LEVEL; break; case SEENWONT: proc_rec_opt(telnet, WONT, c); telnet->state = TOP_LEVEL; break; case SEENDO: proc_rec_opt(telnet, DO, c); telnet->state = TOP_LEVEL; break; case SEENDONT: proc_rec_opt(telnet, DONT, c); telnet->state = TOP_LEVEL; break; case SEENSB: telnet->sb_opt = c; telnet->sb_len = 0; telnet->state = SUBNEGOT; break; case SUBNEGOT: if (c == IAC) telnet->state = SUBNEG_IAC; else { subneg_addchar: if (telnet->sb_len >= telnet->sb_size) { telnet->sb_size += SB_DELTA; telnet->sb_buf = sresize(telnet->sb_buf, telnet->sb_size, unsigned char); } telnet->sb_buf[telnet->sb_len++] = c; telnet->state = SUBNEGOT; /* in case we came here by goto */ } break; case SUBNEG_IAC: if (c != SE) goto subneg_addchar; /* yes, it's a hack, I know, but... */ else { process_subneg(telnet); telnet->state = TOP_LEVEL; } break; } }
static void do_telnet_read (char *buf, int len) { static enum { TOPLEVEL, SEENIAC, SEENWILL, SEENWONT, SEENDO, SEENDONT, SEENSB, SUBNEGOT, SUBNEG_IAC, SEENCR } state = TOPLEVEL; char b[10]; while (len--) { int c = (unsigned char) *buf++; switch (state) { case TOPLEVEL: case SEENCR: if (c == 0 && state == SEENCR) state = TOPLEVEL; else if (c == IAC) state = SEENIAC; else { b[0] = c; if (!in_synch) c_write (b, 1); if (c == 13) state = SEENCR; else state = TOPLEVEL; } break; case SEENIAC: if (c == DO) state = SEENDO; else if (c == DONT) state = SEENDONT; else if (c == WILL) state = SEENWILL; else if (c == WONT) state = SEENWONT; else if (c == SB) state = SEENSB; else state = TOPLEVEL; /* we really ignore _everything_ else! */ break; case SEENWILL: proc_rec_opt (WILL, c); state = TOPLEVEL; break; case SEENWONT: proc_rec_opt (WONT, c); state = TOPLEVEL; break; case SEENDO: proc_rec_opt (DO, c); state = TOPLEVEL; break; case SEENDONT: proc_rec_opt (DONT, c); state = TOPLEVEL; break; case SEENSB: sb_opt = c; sb_len = 0; state = SUBNEGOT; break; case SUBNEGOT: if (c == IAC) state = SUBNEG_IAC; else { subneg_addchar: if (sb_len >= sb_size) { char *newbuf; sb_size += SB_DELTA; newbuf = (sb_buf ? realloc(sb_buf, sb_size) : malloc(sb_size)); if (newbuf) sb_buf = newbuf; else sb_size -= SB_DELTA; } if (sb_len < sb_size) sb_buf[sb_len++] = c; state = SUBNEGOT; /* in case we came here by goto */ } break; case SUBNEG_IAC: if (c != SE) goto subneg_addchar; /* yes, it's a hack, I know, but... */ else { process_subneg(); state = TOPLEVEL; } break; } } }