// Switches to "normal, or non-password mode. func (me *Client) NormalMode() telnet.Event { // When the server wants the client to start local echoing again, it s}s // "IAC WONT ECHO" - the client must respond to this with "IAC DONT ECHO". // Again don't use Q state machine. me.telnet.TelnetSendBytes(t.TELNET_IAC, t.TELNET_WONT, t.TELNET_TELOPT_ECHO) tev, _, _ := me.TryReadEvent(100) if tev != nil && !telnet.IsEventType(tev, t.TELNET_DONT_EVENT) { return tev } return nil }
// Switches to "password" mode. func (me *Client) PasswordMode() telnet.Event { // The server sends "IAC WILL ECHO", meaning "I, the server, will do any // echoing from now on." The client should acknowledge this with an IAC DO // ECHO, and then stop putting echoed text in the input buffer. // It should also do whatever is appropriate for password entry to the input // box thing - for example, it might * it out. Text entered in server-echoes // mode should also not be placed any command history. // don't use the Q state machne for echos me.telnet.TelnetSendBytes(t.TELNET_IAC, t.TELNET_WILL, t.TELNET_TELOPT_ECHO) tev, _, _ := me.TryReadEvent(100) if tev != nil && !telnet.IsEventType(tev, t.TELNET_DO_EVENT) { return tev } return nil }
// Negotiate NAWS (window size) support func (me *Client) SetupNAWS() telnet.Event { ok, tev := me.SetupNegotiate(1000, t.TELNET_DO, t.TELNET_TELOPT_NAWS, t.TELNET_WILL_EVENT, t.TELNET_WONT_EVENT) if !ok { return tev } tev2, _, _ := me.TryReadEvent(1000) if (tev2 == nil) || (!telnet.IsEventType(tev2, t.TELNET_NAWS_EVENT)) { return tev2 } nawsevent, ok := tev2.(*telnet.NAWSEvent) if ok { me.info.w = nawsevent.W me.info.h = nawsevent.H monolog.Info("Client %d window size #{%d}x#{%d}", me.id, me.info.w, me.info.h) me.info.naws = true } return nil }
// Negotiate MTTS/TTYPE (TERMINAL TYPE) support func (me *Client) SetupTType() telnet.Event { me.info.terminals = nil ok, tev := me.SetupNegotiate(1000, t.TELNET_DO, t.TELNET_TELOPT_TTYPE, t.TELNET_WILL_EVENT, t.TELNET_WONT_EVENT) if !ok { return tev } var last string = "none" var now string = "" for last != now { last = now me.telnet.TelnetTTypeSend() var tev2 telnet.Event = nil // Some clients (like KildClient, but not TinTin or telnet), // insist on spamming useless NUL characters // here... So we have to retry a few times to get a ttype_is // throwing away any undesirable junk in between. GET_TTYPE: for index := 0; index < 3; index++ { tev2, _, _ = me.TryReadEvent(1000) if tev2 != nil { etyp := telnet.EventTypeOf(tev2) monolog.Info("Waiting for TTYPE: %T %v %d", tev2, tev2, etyp) if telnet.IsEventType(tev2, t.TELNET_TTYPE_EVENT) { monolog.Info("TTYPE received: %T %v %d", tev2, tev2, etyp) break GET_TTYPE } } else { // and some clients don't respond, even monolog.Info("Waiting for TTYPE: %T", tev2) } } if tev2 == nil || !telnet.IsEventType(tev2, t.TELNET_TTYPE_EVENT) { etyp := telnet.EventTypeOf(tev2) monolog.Warning("Received no TTYPE: %T %v %d", tev2, tev2, etyp) return tev2 } ttypeevent := tev2.(*telnet.TTypeEvent) now = ttypeevent.Name if !me.HasTerminal(now) { me.info.terminals = append(me.info.terminals, now) } me.info.terminal = now } monolog.Info("Client %d supports terminals %v", me.id, me.info.terminals) monolog.Info("Client %d active terminal %v", me.id, me.info.terminal) // MTTS support for i := range me.info.terminals { term := me.info.terminals[i] monolog.Info("Checking MTTS support: %s", term) if strings.HasPrefix(term, "MTTS ") { // it's an mtts terminal strnum := strings.TrimPrefix(term, "MTTS ") num, err := strconv.Atoi(strnum) if err == nil { me.info.mtts = num monolog.Info("Client %d supports mtts %d", me.id, me.info.mtts) } else { monolog.Warning("Client %d could not parse mtts %s %v", me.id, strnum, err) } } } me.info.ttype = true return nil }