179 lines
5.7 KiB
JavaScript
179 lines
5.7 KiB
JavaScript
// Generated by CoffeeScript 2.6.1
|
|
(function() {
|
|
// telnetInput.coffee
|
|
// Copyright 2017 Patrick Meade.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
//----------------------------------------------------------------------------
|
|
var DEFAULT_SUBNEGOTIATION_BUFFER_SIZE, DEFAULT_SUBNEGOTIATION_ERROR_POLICY, TELNET_COMMAND, TELNET_DATA, TELNET_DO, TELNET_DONT, TELNET_IAC, TELNET_OPTION, TELNET_SUBNEG, TELNET_SUBNEG_COMMAND, TELNET_SUB_BEGIN, TELNET_SUB_END, TELNET_WILL, TELNET_WONT, TelnetInput, Transform;
|
|
|
|
DEFAULT_SUBNEGOTIATION_BUFFER_SIZE = 8192;
|
|
|
|
DEFAULT_SUBNEGOTIATION_ERROR_POLICY = "keepBoth";
|
|
|
|
TELNET_COMMAND = "TELNET_COMMAND";
|
|
|
|
TELNET_DATA = "TELNET_DATA";
|
|
|
|
TELNET_OPTION = "TELNET_OPTION";
|
|
|
|
TELNET_SUBNEG = "TELNET_SUBNEG";
|
|
|
|
TELNET_SUBNEG_COMMAND = "TELNET_SUBNEG_COMMAND";
|
|
|
|
TELNET_DO = 253;
|
|
|
|
TELNET_DONT = 254;
|
|
|
|
TELNET_IAC = 255;
|
|
|
|
TELNET_SUB_BEGIN = 250;
|
|
|
|
TELNET_SUB_END = 240;
|
|
|
|
TELNET_WILL = 251;
|
|
|
|
TELNET_WONT = 252;
|
|
|
|
({Transform} = require("stream"));
|
|
|
|
TelnetInput = class TelnetInput extends Transform {
|
|
constructor(opt) {
|
|
var options;
|
|
options = opt || {};
|
|
super(options);
|
|
this.state = TELNET_DATA;
|
|
this.subBufSize = options.bufferSize || DEFAULT_SUBNEGOTIATION_BUFFER_SIZE;
|
|
this.subBuf = Buffer.alloc(this.subBufSize);
|
|
this.errorPolicy = options.errorPolicy || DEFAULT_SUBNEGOTIATION_ERROR_POLICY;
|
|
}
|
|
|
|
_transform(chunk, encoding, callback) {
|
|
var byte, i, len;
|
|
this.dataBuf = Buffer.alloc(chunk.length * 2);
|
|
this.dataBufIndex = 0;
|
|
for (i = 0, len = chunk.length; i < len; i++) {
|
|
byte = chunk[i];
|
|
this._handle(byte);
|
|
}
|
|
if (this.dataBufIndex > 0) {
|
|
this.push(this.dataBuf.slice(0, this.dataBufIndex));
|
|
}
|
|
return callback();
|
|
}
|
|
|
|
_handle(chunkData) {
|
|
switch (this.state) {
|
|
case TELNET_DATA:
|
|
switch (chunkData) {
|
|
case TELNET_IAC:
|
|
return this.state = TELNET_COMMAND;
|
|
default:
|
|
this.dataBuf[this.dataBufIndex] = chunkData;
|
|
return this.dataBufIndex++;
|
|
}
|
|
break;
|
|
case TELNET_COMMAND:
|
|
switch (chunkData) {
|
|
case TELNET_IAC:
|
|
this.state = TELNET_DATA;
|
|
this.dataBuf[this.dataBufIndex] = TELNET_IAC;
|
|
return this.dataBufIndex++;
|
|
case TELNET_DO:
|
|
case TELNET_DONT:
|
|
case TELNET_WILL:
|
|
case TELNET_WONT:
|
|
case TELNET_SUB_BEGIN:
|
|
this.state = TELNET_OPTION;
|
|
return this.command = chunkData;
|
|
default:
|
|
this.state = TELNET_DATA;
|
|
return this.emit("command", chunkData);
|
|
}
|
|
break;
|
|
case TELNET_OPTION:
|
|
switch (this.command) {
|
|
case TELNET_DO:
|
|
this.state = TELNET_DATA;
|
|
return this.emit("do", chunkData);
|
|
case TELNET_DONT:
|
|
this.state = TELNET_DATA;
|
|
return this.emit("dont", chunkData);
|
|
case TELNET_WILL:
|
|
this.state = TELNET_DATA;
|
|
return this.emit("will", chunkData);
|
|
case TELNET_WONT:
|
|
this.state = TELNET_DATA;
|
|
return this.emit("wont", chunkData);
|
|
case TELNET_SUB_BEGIN:
|
|
this.state = TELNET_SUBNEG;
|
|
this.option = chunkData;
|
|
this.subBufIndex = 0;
|
|
return this.subOverflowEmit = false;
|
|
}
|
|
break;
|
|
case TELNET_SUBNEG:
|
|
switch (chunkData) {
|
|
case TELNET_IAC:
|
|
return this.state = TELNET_SUBNEG_COMMAND;
|
|
default:
|
|
return this._handleSub(chunkData);
|
|
}
|
|
break;
|
|
case TELNET_SUBNEG_COMMAND:
|
|
switch (chunkData) {
|
|
case TELNET_IAC:
|
|
this.state = TELNET_SUBNEG;
|
|
return this._handleSub(TELNET_IAC);
|
|
case TELNET_SUB_END:
|
|
this.state = TELNET_DATA;
|
|
return this.emit("sub", this.option, this.subBuf.slice(0, this.subBufIndex));
|
|
default:
|
|
this.state = TELNET_SUBNEG;
|
|
this.emit("error", new Error("expected IAC or SE"));
|
|
switch (this.errorPolicy) {
|
|
case "discardBoth":
|
|
break;
|
|
case "keepData":
|
|
return this._handleSub(chunkData);
|
|
default:
|
|
// "keepBoth"
|
|
this._handleSub(TELNET_IAC);
|
|
return this._handleSub(chunkData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_handleSub(subByte) {
|
|
if (this.subBufIndex >= this.subBufSize) {
|
|
if (!this.subOverflowEmit) {
|
|
this.subOverflowEmit = true;
|
|
this.emit("error", new Error("subnegotiation buffer overflow"));
|
|
}
|
|
return;
|
|
}
|
|
this.subBuf[this.subBufIndex] = subByte;
|
|
return this.subBufIndex++;
|
|
}
|
|
|
|
};
|
|
|
|
exports.TelnetInput = TelnetInput;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// end of telnetInput.coffee
|
|
|
|
}).call(this);
|