package net import ( "bufio" "bytes" "io" "net" "strings" ) type Conn interface { ReadMessage() (string, error) io.Writer io.Closer SetEcho(bool) error } type tcpConn struct { conn net.Conn reader *bufio.Reader echoOff bool } func newTCPConn(conn net.Conn) *tcpConn { return &tcpConn{ conn: conn, reader: bufio.NewReader(conn), } } func (t *tcpConn) ReadMessage() (string, error) { line, err := t.reader.ReadString('\n') if err != nil { return "", err } line = strings.TrimRight(line, "\r\n") line = stripIAC(line) if t.echoOff { t.conn.Write([]byte("\r\n")) } return line, nil } func (t *tcpConn) Write(b []byte) (int, error) { return t.conn.Write(b) } func (t *tcpConn) Close() error { return t.conn.Close() } func (t *tcpConn) SetEcho(on bool) error { t.echoOff = !on if on { return t.writeTelnetCmd(wont, echo) } return t.writeTelnetCmd(will, echo) } const ( iac = 255 will = 251 wont = 252 do = 253 dont = 254 sb = 250 se = 240 echo = 1 ) func (t *tcpConn) writeTelnetCmd(cmd, opt byte) error { _, err := t.conn.Write([]byte{iac, cmd, opt}) return err } func stripIAC(s string) string { b := []byte(s) var out []byte i := 0 iacSE := []byte{iac, se} for i < len(b) { if b[i] == iac && i+2 < len(b) { if b[i+1] == sb { end := bytes.Index(b[i+2:], iacSE) if end >= 0 { i += end + 4 continue } } i += 3 continue } if b[i] == iac { i++ continue } out = append(out, b[i]) i++ } return string(out) }