Sync up with master
This commit is contained in:
commit
19b6f93be4
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"runtimeExecutable": "/home/nuskooler/.local/share/rtx/installs/nodejs/16.20.2/bin/node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"program": "${workspaceFolder}/main.js"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -24,7 +24,7 @@ function ANSIEscapeParser(options) {
|
|||
this.graphicRendition = {};
|
||||
|
||||
this.parseState = {
|
||||
re: /(?:\x1b\x5b)([?=;0-9]*?)([ABCDHJKfhlmnpsutEFGST])/g, // eslint-disable-line no-control-regex
|
||||
re: /(?:\x1b)(?:(?:\x5b([?=;0-9]*?)([ABCDEFGfHJKLmMsSTuUYZt@PXhlnpt]))|([78DEHM]))/g, // eslint-disable-line no-control-regex
|
||||
};
|
||||
|
||||
options = miscUtil.valueWithDefault(options, {
|
||||
|
@ -77,10 +77,24 @@ function ANSIEscapeParser(options) {
|
|||
self.clearScreen = function () {
|
||||
self.column = 1;
|
||||
self.row = 1;
|
||||
self.positionUpdated();
|
||||
self.emit('clear screen');
|
||||
};
|
||||
|
||||
self.positionUpdated = function () {
|
||||
if (self.row > self.termHeight) {
|
||||
if (this.savedPosition) {
|
||||
this.savedPosition.row -= self.row - self.termHeight;
|
||||
}
|
||||
self.emit('scroll', self.row - self.termHeight);
|
||||
self.row = self.termHeight;
|
||||
} else if (self.row < 1) {
|
||||
if (this.savedPosition) {
|
||||
this.savedPosition.row -= self.row - 1;
|
||||
}
|
||||
self.emit('scroll', -(self.row - 1));
|
||||
self.row = 1;
|
||||
}
|
||||
self.emit('position update', self.row, self.column);
|
||||
};
|
||||
|
||||
|
@ -231,7 +245,7 @@ function ANSIEscapeParser(options) {
|
|||
self.parseState = {
|
||||
// ignore anything past EOF marker, if any
|
||||
buffer: input.split(String.fromCharCode(0x1a), 1)[0],
|
||||
re: /(?:\x1b\x5b)([?=;0-9]*?)([ABCDHJKfhlmnpsutEFGST])/g, // eslint-disable-line no-control-regex
|
||||
re: /(?:\x1b)(?:(?:\x5b([?=;0-9]*?)([ABCDEFGfHJKLmMsSTuUYZt@PXhlnpt]))|([78DEHM]))/g, // eslint-disable-line no-control-regex
|
||||
stop: false,
|
||||
};
|
||||
};
|
||||
|
@ -271,9 +285,46 @@ function ANSIEscapeParser(options) {
|
|||
opCode = match[2];
|
||||
args = match[1].split(';').map(v => parseInt(v, 10)); // convert to array of ints
|
||||
|
||||
escape(opCode, args);
|
||||
// Handle the case where there is no bracket
|
||||
if (!_.isNil(match[3])) {
|
||||
opCode = match[3];
|
||||
args = [];
|
||||
// no bracket
|
||||
switch (opCode) {
|
||||
// save cursor position
|
||||
case '7':
|
||||
escape('s', args);
|
||||
break;
|
||||
// restore cursor position
|
||||
case '8':
|
||||
escape('u', args);
|
||||
break;
|
||||
|
||||
// scroll up
|
||||
case 'D':
|
||||
escape('S', args);
|
||||
break;
|
||||
|
||||
// move to next line
|
||||
case 'E':
|
||||
// functonality is the same as ESC [ E
|
||||
escape(opCode, args);
|
||||
break;
|
||||
|
||||
// create a tab at current cursor position
|
||||
case 'H':
|
||||
literal('\t');
|
||||
break;
|
||||
|
||||
// scroll down
|
||||
case 'M':
|
||||
escape('T', args);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
escape(opCode, args);
|
||||
}
|
||||
|
||||
//self.emit('chunk', match[0]);
|
||||
self.emit('control', match[0], opCode, args);
|
||||
}
|
||||
} while (0 !== re.lastIndex);
|
||||
|
@ -281,8 +332,8 @@ function ANSIEscapeParser(options) {
|
|||
if (pos < buffer.length) {
|
||||
var lastBit = buffer.slice(pos);
|
||||
|
||||
// :TODO: check for various ending LF's, not just DOS \r\n
|
||||
if ('\r\n' === lastBit.slice(-2).toString()) {
|
||||
// handles either \r\n or \n
|
||||
if ('\n' === lastBit.slice(-1).toString()) {
|
||||
switch (self.trailingLF) {
|
||||
case 'default':
|
||||
//
|
||||
|
@ -290,14 +341,14 @@ function ANSIEscapeParser(options) {
|
|||
// if we're going to end on termHeight
|
||||
//
|
||||
if (this.termHeight === self.row) {
|
||||
lastBit = lastBit.slice(0, -2);
|
||||
lastBit = lastBit.slice(0, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'omit':
|
||||
case 'no':
|
||||
case false:
|
||||
lastBit = lastBit.slice(0, -2);
|
||||
lastBit = lastBit.slice(0, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -308,48 +359,6 @@ function ANSIEscapeParser(options) {
|
|||
self.emit('complete');
|
||||
};
|
||||
|
||||
/*
|
||||
self.parse = function(buffer, savedRe) {
|
||||
// :TODO: ensure this conforms to ANSI-BBS / CTerm / bansi.txt for movement/etc.
|
||||
// :TODO: move this to "constants" section @ top
|
||||
var re = /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g;
|
||||
var pos = 0;
|
||||
var match;
|
||||
var opCode;
|
||||
var args;
|
||||
|
||||
// ignore anything past EOF marker, if any
|
||||
buffer = buffer.split(String.fromCharCode(0x1a), 1)[0];
|
||||
|
||||
do {
|
||||
pos = re.lastIndex;
|
||||
match = re.exec(buffer);
|
||||
|
||||
if(null !== match) {
|
||||
if(match.index > pos) {
|
||||
parseMCI(buffer.slice(pos, match.index));
|
||||
}
|
||||
|
||||
opCode = match[2];
|
||||
args = getArgArray(match[1].split(';'));
|
||||
|
||||
escape(opCode, args);
|
||||
|
||||
self.emit('chunk', match[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} while(0 !== re.lastIndex);
|
||||
|
||||
if(pos < buffer.length) {
|
||||
parseMCI(buffer.slice(pos));
|
||||
}
|
||||
|
||||
self.emit('complete');
|
||||
};
|
||||
*/
|
||||
|
||||
function escape(opCode, args) {
|
||||
let arg;
|
||||
|
||||
|
@ -382,6 +391,35 @@ function ANSIEscapeParser(options) {
|
|||
self.moveCursor(-arg, 0);
|
||||
break;
|
||||
|
||||
// line feed
|
||||
case 'E':
|
||||
arg = isNaN(args[0]) ? 1 : args[0];
|
||||
if (this.row + arg > this.termHeight) {
|
||||
this.emit('scroll', arg - (this.termHeight - this.row));
|
||||
self.moveCursor(0, this.termHeight);
|
||||
} else {
|
||||
self.moveCursor(0, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
// reverse line feed
|
||||
case 'F':
|
||||
arg = isNaN(args[0]) ? 1 : args[0];
|
||||
if (this.row - arg < 1) {
|
||||
this.emit('scroll', -(arg - this.row));
|
||||
self.moveCursor(0, 1 - this.row);
|
||||
} else {
|
||||
self.moveCursor(0, -arg);
|
||||
}
|
||||
break;
|
||||
|
||||
// absolute horizontal cursor position
|
||||
case 'G':
|
||||
arg = isNaN(args[0]) ? 1 : args[0];
|
||||
self.column = Math.max(1, arg);
|
||||
self.positionUpdated();
|
||||
break;
|
||||
|
||||
case 'f': // horiz & vertical
|
||||
case 'H': // cursor position
|
||||
//self.row = args[0] || 1;
|
||||
|
@ -392,14 +430,32 @@ function ANSIEscapeParser(options) {
|
|||
self.positionUpdated();
|
||||
break;
|
||||
|
||||
// save position
|
||||
case 's':
|
||||
self.saveCursorPosition();
|
||||
// erase display/screen
|
||||
case 'J':
|
||||
if (isNaN(args[0]) || 0 === args[0]) {
|
||||
self.emit('erase rows', self.row, self.termHeight);
|
||||
} else if (1 === args[0]) {
|
||||
self.emit('erase rows', 1, self.row);
|
||||
} else if (2 === args[0]) {
|
||||
self.clearScreen();
|
||||
}
|
||||
break;
|
||||
|
||||
// restore position
|
||||
case 'u':
|
||||
self.restoreCursorPosition();
|
||||
// erase text in line
|
||||
case 'K':
|
||||
if (isNaN(args[0]) || 0 === args[0]) {
|
||||
self.emit('erase columns', self.row, self.column, self.termWidth);
|
||||
} else if (1 === args[0]) {
|
||||
self.emit('erase columns', self.row, 1, self.column);
|
||||
} else if (2 === args[0]) {
|
||||
self.emit('erase columns', self.row, 1, self.termWidth);
|
||||
}
|
||||
break;
|
||||
|
||||
// insert line
|
||||
case 'L':
|
||||
arg = isNaN(args[0]) ? 1 : args[0];
|
||||
self.emit('insert line', self.row, arg);
|
||||
break;
|
||||
|
||||
// set graphic rendition
|
||||
|
@ -471,14 +527,50 @@ function ANSIEscapeParser(options) {
|
|||
self.emit('sgr update', self.graphicRendition);
|
||||
break; // m
|
||||
|
||||
// :TODO: s, u, K
|
||||
// save position
|
||||
case 's':
|
||||
self.saveCursorPosition();
|
||||
break;
|
||||
|
||||
// erase display/screen
|
||||
case 'J':
|
||||
// :TODO: Handle other 'J' types!
|
||||
if (2 === args[0]) {
|
||||
// Scroll up
|
||||
case 'S':
|
||||
arg = isNaN(args[0]) ? 1 : args[0];
|
||||
self.emit('scroll', arg);
|
||||
break;
|
||||
|
||||
// Scroll down
|
||||
case 'T':
|
||||
arg = isNaN(args[0]) ? 1 : args[0];
|
||||
self.emit('scroll', -arg);
|
||||
break;
|
||||
|
||||
// restore position
|
||||
case 'u':
|
||||
self.restoreCursorPosition();
|
||||
break;
|
||||
|
||||
// clear
|
||||
case 'U':
|
||||
self.clearScreen();
|
||||
}
|
||||
break;
|
||||
|
||||
// delete line
|
||||
// TODO: how should we handle 'M'?
|
||||
case 'Y':
|
||||
arg = isNaN(args[0]) ? 1 : args[0];
|
||||
self.emit('delete line', self.row, arg);
|
||||
break;
|
||||
|
||||
// back tab
|
||||
case 'Z':
|
||||
// calculate previous tabstop
|
||||
self.column = Math.max(1, self.column - (self.column % 8 || 8));
|
||||
self.positionUpdated();
|
||||
break;
|
||||
case '@':
|
||||
// insert column(s)
|
||||
arg = isNaN(args[0]) ? 1 : args[0];
|
||||
self.emit('insert columns', self.row, self.column, arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,17 +208,17 @@ module.exports = class ArchiveUtil {
|
|||
// pty.js doesn't currently give us a error when things fail,
|
||||
// so we have this horrible, horrible hack:
|
||||
let err;
|
||||
proc.once('data', d => {
|
||||
proc.onData(d => {
|
||||
if (_.isString(d) && d.startsWith('execvp(3) failed.')) {
|
||||
err = Errors.ExternalProcess(`${action} failed: ${d.trim()}`);
|
||||
}
|
||||
});
|
||||
|
||||
proc.once('exit', exitCode => {
|
||||
proc.onExit(exitEvent => {
|
||||
return cb(
|
||||
exitCode
|
||||
exitEvent.exitCode
|
||||
? Errors.ExternalProcess(
|
||||
`${action} failed with exit code: ${exitCode}`
|
||||
`${action} failed with exit code: ${exitEvent.exitCode}`
|
||||
)
|
||||
: err
|
||||
);
|
||||
|
@ -358,10 +358,12 @@ module.exports = class ArchiveUtil {
|
|||
output += data;
|
||||
});
|
||||
|
||||
proc.once('exit', exitCode => {
|
||||
if (exitCode) {
|
||||
proc.onExit(exitEvent => {
|
||||
if (exitEvent.exitCode) {
|
||||
return cb(
|
||||
Errors.ExternalProcess(`List failed with exit code: ${exitCode}`)
|
||||
Errors.ExternalProcess(
|
||||
`List failed with exit code: ${exitEvent.exitCode}`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
68
core/art.js
68
core/art.js
|
@ -316,6 +316,74 @@ function display(client, art, options, cb) {
|
|||
}
|
||||
});
|
||||
|
||||
// Remove any MCI's that are in erased rows
|
||||
ansiParser.on('erase row', (startRow, endRow) => {
|
||||
_.forEach(mciMap, (mciInfo, mapKey) => {
|
||||
if (mciInfo.position[0] >= startRow && mciInfo.position[0] <= endRow) {
|
||||
delete mciMap[mapKey];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Remove any MCI's that are in erased columns
|
||||
ansiParser.on('erase columns', (row, startCol, endCol) => {
|
||||
_.forEach(mciMap, (mciInfo, mapKey) => {
|
||||
if (
|
||||
mciInfo.position[0] === row &&
|
||||
mciInfo.position[1] >= startCol &&
|
||||
mciInfo.position[1] <= endCol
|
||||
) {
|
||||
delete mciMap[mapKey];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ansiParser.on('insert columns', (row, startCol, numCols) => {
|
||||
_.forEach(mciMap, (mciInfo, mapKey) => {
|
||||
if (mciInfo.position[0] === row && mciInfo.position[1] >= startCol) {
|
||||
mciInfo.position[1] += numCols;
|
||||
if (mciInfo.position[1] > client.term.termWidth) {
|
||||
delete mciMap[mapKey];
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Clear the screen, removing any MCI's
|
||||
ansiParser.on('clear screen', () => {
|
||||
_.forEach(mciMap, (mciInfo, mapKey) => {
|
||||
delete mciMap[mapKey];
|
||||
});
|
||||
});
|
||||
|
||||
ansiParser.on('scroll', scrollY => {
|
||||
_.forEach(mciMap, mciInfo => {
|
||||
mciInfo.position[0] -= scrollY;
|
||||
});
|
||||
});
|
||||
|
||||
ansiParser.on('insert line', (row, numLines) => {
|
||||
_.forEach(mciMap, mciInfo => {
|
||||
if (mciInfo.position[0] >= row) {
|
||||
mciInfo.position[0] += numLines;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ansiParser.on('delete line', (row, numLines) => {
|
||||
_.forEach(mciMap, (mciInfo, mapKey) => {
|
||||
if (mciInfo.position[0] >= row) {
|
||||
if (mciInfo.position[0] < row + numLines) {
|
||||
// unlike scrolling, the rows are actually gone,
|
||||
// so we need to delete any MCI's that are in them
|
||||
delete mciMap[mapKey];
|
||||
} else {
|
||||
mciInfo.position[0] -= numLines;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ansiParser.on('literal', literal => client.term.write(literal, false));
|
||||
ansiParser.on('control', control => client.term.rawWrite(control));
|
||||
|
||||
|
|
12
core/door.js
12
core/door.js
|
@ -115,9 +115,10 @@ module.exports = class Door {
|
|||
spawnOptions
|
||||
);
|
||||
|
||||
prePty.once('exit', exitCode => {
|
||||
prePty.onExit(exitEvent => {
|
||||
const { exitCode, signal } = exitEvent;
|
||||
this.client.log.info(
|
||||
{ exitCode: exitCode },
|
||||
{ exitCode, signal },
|
||||
'Door pre-command exited'
|
||||
);
|
||||
return callback(null);
|
||||
|
@ -167,7 +168,7 @@ module.exports = class Door {
|
|||
|
||||
this.doorPty.onData(this.doorDataHandler.bind(this));
|
||||
|
||||
this.doorPty.once('close', () => {
|
||||
this.doorPty.onExit((/*exitEvent*/) => {
|
||||
return this.restoreIo(this.doorPty);
|
||||
});
|
||||
} else if ('socket' === this.io) {
|
||||
|
@ -180,8 +181,9 @@ module.exports = class Door {
|
|||
);
|
||||
}
|
||||
|
||||
this.doorPty.once('exit', exitCode => {
|
||||
this.client.log.info({ exitCode: exitCode }, 'Door exited');
|
||||
this.doorPty.onExit(exitEvent => {
|
||||
const { exitCode, signal } = exitEvent;
|
||||
this.client.log.info({ exitCode, signal }, 'Door exited');
|
||||
|
||||
if (this.sockServer) {
|
||||
this.sockServer.close();
|
||||
|
|
|
@ -167,17 +167,21 @@ class ScheduledEvent {
|
|||
return cb(e);
|
||||
}
|
||||
|
||||
proc.once('exit', exitCode => {
|
||||
if (exitCode) {
|
||||
proc.onExit(exitEvent => {
|
||||
if (exitEvent.exitCode) {
|
||||
Log.warn(
|
||||
{ eventName: this.name, action: this.action, exitCode: exitCode },
|
||||
{
|
||||
eventName: this.name,
|
||||
action: this.action,
|
||||
exitCode: exitEvent.exitCode,
|
||||
},
|
||||
'Bad exit code while performing scheduled event action'
|
||||
);
|
||||
}
|
||||
return cb(
|
||||
exitCode
|
||||
exitEvent.exitCode
|
||||
? Errors.ExternalProcess(
|
||||
`Bad exit code while performing scheduled event action: ${exitCode}`
|
||||
`Bad exit code while performing scheduled event action: ${exitEvent.exitCode}`
|
||||
)
|
||||
: null
|
||||
);
|
||||
|
|
|
@ -485,13 +485,10 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
|||
}
|
||||
});
|
||||
|
||||
externalProc.once('close', () => {
|
||||
return this.restorePipeAfterExternalProc();
|
||||
});
|
||||
|
||||
externalProc.once('exit', exitCode => {
|
||||
externalProc.onExit(exitEvent => {
|
||||
const { exitCode, signal } = exitEvent;
|
||||
this.client.log.debug(
|
||||
{ cmd: cmd, args: args, exitCode: exitCode },
|
||||
{ cmd: cmd, args: args, exitCode, signal },
|
||||
'Process exited'
|
||||
);
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
"minimist": "^1.2.6",
|
||||
"moment": "2.29.4",
|
||||
"nntp-server": "3.1.0",
|
||||
"node-pty": "0.10.1",
|
||||
"node-pty": "1.0.0",
|
||||
"nodemailer": "6.7.7",
|
||||
"otplib": "11.0.1",
|
||||
"qrcode-generator": "^1.4.4",
|
||||
|
@ -65,8 +65,8 @@
|
|||
"sanitize-filename": "^1.6.3",
|
||||
"sqlite3": "5.1.6",
|
||||
"sqlite3-trans": "1.3.0",
|
||||
"string-strip-html": "8.4.0",
|
||||
"ssh2": "1.14.0",
|
||||
"string-strip-html": "8.4.0",
|
||||
"systeminformation": "5.21.7",
|
||||
"telnet-socket": "0.2.4",
|
||||
"temptmp": "^1.1.0",
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -1921,12 +1921,12 @@ node-int64@^0.4.0:
|
|||
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
|
||||
integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
|
||||
|
||||
node-pty@0.10.1:
|
||||
version "0.10.1"
|
||||
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.1.tgz#cd05d03a2710315ec40221232ec04186f6ac2c6d"
|
||||
integrity sha512-JTdtUS0Im/yRsWJSx7yiW9rtpfmxqxolrtnyKwPLI+6XqTAPW/O2MjS8FYL4I5TsMbH2lVgDb2VMjp+9LoQGNg==
|
||||
node-pty@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.0.0.tgz#7daafc0aca1c4ca3de15c61330373af4af5861fd"
|
||||
integrity sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA==
|
||||
dependencies:
|
||||
nan "^2.14.0"
|
||||
nan "^2.17.0"
|
||||
|
||||
nodemailer@6.7.7:
|
||||
version "6.7.7"
|
||||
|
|
Loading…
Reference in New Issue