NuSkooler / telnet-socket

A standards compliant Telnet implementation for Node.js
BSD 2-Clause "Simplified" License
6 stars 1 forks source link

telnet server #2

Closed theflyingape closed 4 years ago

theflyingape commented 4 years ago

Greetings, I am the author of Dank Domain (www.ddgame.us) and I am pursuing to integrate a telnet service in place of using the Linux telnet service. Your library works fine to do this, thank you, but it feels like I had to hack this somewhat to get the terminal size upon connection. A code snippet follows:

let telnet = new TelnetSocket(socket)
telnet.do.naws()
telnet.do.sga()
telnet.do.ttype()
telnet.do.new_environ()
telnet.dont.echo()  // client don't local echo
telnet.will.echo()  // app will echo
telnet.will.sga()

telnet.on('WILL', command => {
    switch (command.optionName) {
        case 'NAWS':
            let buf = telnet.buffers.splice(0, 9).toBuffer()
            let rows = 256 * buf[5] + buf[6]
            let cols = 256 * buf[3] + buf[4]
            console.log(`Resize CLASSIC session ${pid} (${rows}x${cols})`)
            term.resize(cols, rows)
            break
    }
})

telnet.on('data', (buff) => {
    let data = buff.toString().replace(/\x00/g, '')
    try {
        term.write(data)
    } catch (err) {
        if (term.pid) {
            console.log(`?FATAL ACTIVE CLASSIC session ${term.pid} socket -> pty error:`, err.message)
            unlock(term.pid)
            socket.destroy()
        }
    }
})

Also, I only receive NAWS once upon connection. If I resize the window during the session, it does not send the window size change. Is this expected behavior with telnet? Secondary, notice I had to replace NULs from the on data buff. I get them after hitting the ENTER key and receive '\x0D\x00'. Is that a trace artifact from SGA, because without SGA it returns an undesirable '\x0D\x0A' sequence in line mode.

NuSkooler commented 4 years ago

@theflyingape Glad you're taking it for a spin (I also take Dank for a spin many times & have it hooked to my board)!

After requesting the client send NAWS (DO NAWS), if the client decides to do so, you should receive a SB with the information in it.

telnet.on('SB', command => {
  if (Options.NAWS === command.option) {
    const { width, height } = command.optionData;
    // do something with width and height
  }
}

For a larger example of all of this and other negotiations, see https://github.com/NuSkooler/enigma-bbs/blob/0.0.11-beta/core/servers/login/telnet.js#L142 (the entire file implements other ANSI-BBS style handling that should also be of interest).

RE: the extra nulls. I'm trying to remember if there is a specific spec for this or if just some clients do it. What client are you using?

BTW: I will be creating a another library soon to share between my MUD-ish/Door I'm working on and ENiGMA BBS, but here is a clip that may help for processing keys/input. You can attached it to data which in return will emit key events: https://hastebin.com/ijidufekek.cs

For more MUD-like in line mode, this can be used something like:

this.termInputKeyPressListener = (ch, key) => {
    key = key || ch;

    if (['backspace', 'delete'].includes(key.name)) {
        if (this.lineBuffer.length) {
            this.lineBuffer = this.lineBuffer.slice(0, -1);
            return this.socket.write('\b \b');
        }
        return;
    }

    if (ch) {
        this.socket.write(this.passwordEchoChar || ch);
    }

    if ('return' === key.name) {
        ch = '\r\n';
    }

    if (!ch) {
        return;
    }

    this.lineBuffer += ch

    let m;
    while ((m = AnyCRLF.exec(this.lineBuffer))) {
        const data = this.lineBuffer.slice(0, m.index);
        this.emit('data', data);
        this.lineBuffer = this.lineBuffer.slice(m.index + m[0].length);
    }
};
theflyingape commented 4 years ago

Ah, did not see any SB event option -- very useful and works for me, thanks. Just using Linux telnet off a bash prompt, using any terminal: gnome-terminal and terminology. My dungeon game uses my npm xvt package for input & output handling, but I prefer to use character over line mode handling. No worries over the NULs, just thought it might be useful to report, if they shouldn't be normally passed along in the on data event.