Compare commits
10 commits
2e9d5071d9
...
29f17aa874
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29f17aa874 | ||
|
|
c38fb5d107 | ||
|
|
9004afebdc | ||
|
|
f2256500e1 | ||
|
|
4940bf86ae | ||
|
|
4059bf2983 | ||
|
|
c4d10ba33d | ||
|
|
2f40fc5387 | ||
|
|
c824ea924c | ||
|
|
5b790718d8 |
8 changed files with 247 additions and 163 deletions
2
Makefile
2
Makefile
|
|
@ -23,7 +23,7 @@ install: all
|
||||||
mkdir -p ${CHROOT}/var/www
|
mkdir -p ${CHROOT}/var/www
|
||||||
cp ${WEBASSETS} ${CHROOT}/var/www
|
cp ${WEBASSETS} ${CHROOT}/var/www
|
||||||
cp rlgwebd.service /usr/lib/systemd/system
|
cp rlgwebd.service /usr/lib/systemd/system
|
||||||
if test ! -f /etc/rlgwebd.conf; cp rlgwebd.conf /etc; fi
|
if test ! -f /etc/rlgwebd.conf; then cp rlgwebd.conf /etc; fi
|
||||||
|
|
||||||
# Libraries are not removed. Something else might be using them.
|
# Libraries are not removed. Something else might be using them.
|
||||||
uninstall:
|
uninstall:
|
||||||
|
|
|
||||||
21
README.txt
21
README.txt
|
|
@ -5,12 +5,11 @@ browser. It is intended to be compatible with dgamelaunch.
|
||||||
|
|
||||||
Node
|
Node
|
||||||
---
|
---
|
||||||
RLGWebD currently works with Node v0.10.
|
RLGWebD is currently being updated to work with Node v10.x.
|
||||||
|
|
||||||
It requires the 'posix', 'pty.js', and 'websocket' modules. Currently,
|
It requires the 'posix', 'node-pty', and 'websocket' modules. Currently,
|
||||||
it expects them to be installed in the global location, which is
|
it expects them to be installed in "/var/local/lib/node_modules". It
|
||||||
"/usr/lib/node_modules". It is planned to eventually use a different
|
is not recommended to run npm as root when installing the modules.
|
||||||
location so that npm will not need to run as root.
|
|
||||||
|
|
||||||
init
|
init
|
||||||
---
|
---
|
||||||
|
|
@ -22,14 +21,11 @@ a proper initscript, but it could form the basis of one.
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
---
|
---
|
||||||
You can set some options by changing some variables in the first few
|
A configuration file is installed at /etc/rlgwebd.conf. It contains a
|
||||||
lines of the rlgwebd script:
|
list of options.
|
||||||
|
|
||||||
Option Variable Default
|
If the domain_name option and the SSL-related options are set, rlgwebd
|
||||||
|
will use HTTPS instead of insecure HTTP.
|
||||||
Chroot path chrootDir /var/dgl
|
|
||||||
Username dropToUser rodney
|
|
||||||
Server port httpPort 8080
|
|
||||||
|
|
||||||
If you change the chroot location, change it in the first line of the
|
If you change the chroot location, change it in the first line of the
|
||||||
Makefile too.
|
Makefile too.
|
||||||
|
|
@ -59,6 +55,7 @@ Running "make install" will:
|
||||||
Copy the C programs and the libraries they need into the chroot
|
Copy the C programs and the libraries they need into the chroot
|
||||||
Install the main RLGWebD script in /usr/local/bin
|
Install the main RLGWebD script in /usr/local/bin
|
||||||
Place the systemd unit file in the proper directory
|
Place the systemd unit file in the proper directory
|
||||||
|
Copy a configuration file into /etc
|
||||||
|
|
||||||
If you don't use systemd, or want to change the installation locations,
|
If you don't use systemd, or want to change the installation locations,
|
||||||
you will have to edit the Makefile.
|
you will have to edit the Makefile.
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
NODE_PATH=/usr/lib/node_modules
|
NODE_PATH=/var/local/lib/node_modules
|
||||||
LOGFILE=/var/log/rlgwebd.log
|
LOGFILE=/var/log/rlgwebd.log
|
||||||
CTLSOCKET=/var/run/rlgwebd.sock
|
CTLSOCKET=/var/run/rlgwebd/rlgwebd.sock
|
||||||
RLGWEBDJS=/usr/local/bin/rlgwebd
|
RLGWEBDJS=/usr/local/bin/rlgwebd
|
||||||
|
|
||||||
export NODE_PATH
|
export NODE_PATH
|
||||||
|
|
|
||||||
160
rlgwebd
160
rlgwebd
|
|
@ -1,35 +1,38 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
var http = require('http');
|
const http = require('http');
|
||||||
var https = require('https');
|
const https = require('https');
|
||||||
var net = require('net');
|
const net = require('net');
|
||||||
var url = require('url');
|
const url = require('url');
|
||||||
var path = require('path');
|
const path = require('path');
|
||||||
var fs = require('fs');
|
const fs = require('fs');
|
||||||
var events = require('events');
|
const events = require('events');
|
||||||
var child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
// Dependencies
|
// Dependencies
|
||||||
var posix = require("posix");
|
const posix = require("posix");
|
||||||
var pty = require("pty.js");
|
const pty = require("node-pty");
|
||||||
var WebSocketServer = require("websocket").server;
|
const WebSocketServer = require("websocket").server;
|
||||||
|
|
||||||
|
const errorcodes = [ "Generic Error", "Not logged in", "Invalid data",
|
||||||
|
"Login failed", "Already playing", "Game launch failed",
|
||||||
|
"Server shutting down", "Game not in progress" ];
|
||||||
|
|
||||||
/* Default options */
|
/* Default options */
|
||||||
var rlgwebd_options = {
|
var rlgwebd_options = {
|
||||||
control_socket: "/var/run/rlgwebd.sock",
|
control_socket: "/var/run/rlgwebd/rlgwebd.sock",
|
||||||
http_port: 8080,
|
port: 8080,
|
||||||
https_port: 8081,
|
|
||||||
chrootDir: "/var/dgl/",
|
chrootDir: "/var/dgl/",
|
||||||
username: "rodney",
|
username: "rodney",
|
||||||
static_root: "/var/www/"
|
static_root: "/var/www/"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Read configuration from a file */
|
/* Read configuration from a file */
|
||||||
var config_file = "/etc/rlgwebd.conf";
|
const config_file = "/etc/rlgwebd.conf";
|
||||||
var config_lines = read_or_die(config_file, "Configuration file").toString().split('\n');
|
var config_lines = read_or_die(config_file, "Configuration file").toString().split('\n');
|
||||||
|
|
||||||
for (var i = 0; i < config_lines.length; i++) {
|
for (let conf_line of config_lines) {
|
||||||
if (config_lines[i].length > 0 && config_lines[i][0] != '#') {
|
if (conf_line.length > 0 && conf_line[0] != '#') {
|
||||||
var config_fields = config_lines[i].split('=');
|
var config_fields = conf_line.split('=');
|
||||||
if (config_fields.length < 2)
|
if (config_fields.length < 2)
|
||||||
continue;
|
continue;
|
||||||
var option_name = config_fields[0].trim();
|
var option_name = config_fields[0].trim();
|
||||||
|
|
@ -44,13 +47,13 @@ if ("domain_name" in rlgwebd_options && "keyfile" in rlgwebd_options &&
|
||||||
"certfile" in rlgwebd_options)
|
"certfile" in rlgwebd_options)
|
||||||
rlgwebd_options["use_https"] = true;
|
rlgwebd_options["use_https"] = true;
|
||||||
|
|
||||||
var clearbufs = [
|
const clearbufs = [
|
||||||
new Buffer([27, 91, 72, 27, 91, 50, 74]), // xterm: CSI H CSI 2J
|
Buffer.from([27, 91, 72, 27, 91, 50, 74]), // xterm: CSI H CSI 2J
|
||||||
new Buffer([27, 91, 72, 27, 91, 74]) // screen: CSI H CSI J
|
Buffer.from([27, 91, 72, 27, 91, 74]) // screen: CSI H CSI J
|
||||||
];
|
];
|
||||||
|
|
||||||
/* Data on the games available. */
|
/* Data on the games available. */
|
||||||
var games = {
|
const games = {
|
||||||
"rogue3": {
|
"rogue3": {
|
||||||
"name": "Rogue V3",
|
"name": "Rogue V3",
|
||||||
"uname": "rogue3",
|
"uname": "rogue3",
|
||||||
|
|
@ -110,7 +113,7 @@ function BaseGame() {
|
||||||
this.watchers = [];
|
this.watchers = [];
|
||||||
/* replaybuf holds the output since the last screen clear, so watchers can
|
/* replaybuf holds the output since the last screen clear, so watchers can
|
||||||
* begin with a complete screen. replaylen is the number of bytes stored. */
|
* begin with a complete screen. replaylen is the number of bytes stored. */
|
||||||
this.replaybuf = new Buffer(1024);
|
this.replaybuf = Buffer.alloc(1024);
|
||||||
this.replaylen = 0;
|
this.replaylen = 0;
|
||||||
/* Time of last activity. */
|
/* Time of last activity. */
|
||||||
this.lasttime = new Date();
|
this.lasttime = new Date();
|
||||||
|
|
@ -126,12 +129,12 @@ BaseGame.prototype.tag = function () {
|
||||||
BaseGame.prototype.framepush = function(chunk) {
|
BaseGame.prototype.framepush = function(chunk) {
|
||||||
/* If this chunk resets the screen, discard what preceded it. */
|
/* If this chunk resets the screen, discard what preceded it. */
|
||||||
if (isclear(chunk)) {
|
if (isclear(chunk)) {
|
||||||
this.replaybuf = new Buffer(1024);
|
this.replaybuf = Buffer.alloc(1024);
|
||||||
this.replaylen = 0;
|
this.replaylen = 0;
|
||||||
}
|
}
|
||||||
/* Make sure there's space. */
|
/* Make sure there's space. */
|
||||||
while (this.replaybuf.length < chunk.length + this.replaylen) {
|
while (this.replaybuf.length < chunk.length + this.replaylen) {
|
||||||
var nbuf = new Buffer(this.replaybuf.length * 2);
|
var nbuf = Buffer.alloc(this.replaybuf.length * 2);
|
||||||
this.replaybuf.copy(nbuf, 0, 0, this.replaylen);
|
this.replaybuf.copy(nbuf, 0, 0, this.replaylen);
|
||||||
this.replaybuf = nbuf;
|
this.replaybuf = nbuf;
|
||||||
if (this.replaybuf.length > 65536) {
|
if (this.replaybuf.length > 65536) {
|
||||||
|
|
@ -211,7 +214,9 @@ function TermSession(gname, pname, wsReq) {
|
||||||
var progressdir = path.join("/dgldir/inprogress", this.gname);
|
var progressdir = path.join("/dgldir/inprogress", this.gname);
|
||||||
this.lock = path.join(progressdir, this.pname + ":node:" + ts + ".ttyrec");
|
this.lock = path.join(progressdir, this.pname + ":node:" + ts + ".ttyrec");
|
||||||
var lmsg = this.term.pid.toString() + '\n' + this.h + '\n' + this.w + '\n';
|
var lmsg = this.term.pid.toString() + '\n' + this.h + '\n' + this.w + '\n';
|
||||||
fs.writeFile(this.lock, lmsg, "utf8");
|
fs.writeFile(this.lock, lmsg, "utf8", function (err) {
|
||||||
|
if (err) tslog("Locking failed: %s", err);
|
||||||
|
});
|
||||||
var ttyrec = path.join("/dgldir/ttyrec", this.pname, this.gname,
|
var ttyrec = path.join("/dgldir/ttyrec", this.pname, this.gname,
|
||||||
ts + ".ttyrec");
|
ts + ".ttyrec");
|
||||||
this.record = fs.createWriteStream(ttyrec, { mode: 0664 });
|
this.record = fs.createWriteStream(ttyrec, { mode: 0664 });
|
||||||
|
|
@ -239,8 +244,8 @@ TermSession.prototype = new BaseGame();
|
||||||
/* Currently this also sends to the player and any watchers. */
|
/* Currently this also sends to the player and any watchers. */
|
||||||
TermSession.prototype.write_ttyrec = function (datastr) {
|
TermSession.prototype.write_ttyrec = function (datastr) {
|
||||||
this.lasttime = new Date();
|
this.lasttime = new Date();
|
||||||
var buf = new Buffer(datastr);
|
var buf = Buffer.from(datastr);
|
||||||
var chunk = new Buffer(buf.length + 12);
|
var chunk = Buffer.alloc(buf.length + 12);
|
||||||
/* TTYREC headers */
|
/* TTYREC headers */
|
||||||
chunk.writeUInt32LE(Math.floor(this.lasttime.getTime() / 1000), 0);
|
chunk.writeUInt32LE(Math.floor(this.lasttime.getTime() / 1000), 0);
|
||||||
chunk.writeUInt32LE(1000 * (this.lasttime.getTime() % 1000), 4);
|
chunk.writeUInt32LE(1000 * (this.lasttime.getTime() % 1000), 4);
|
||||||
|
|
@ -274,7 +279,7 @@ TermSession.prototype.input_msg = function (message) {
|
||||||
if (hexstr.length % 2 != 0) {
|
if (hexstr.length % 2 != 0) {
|
||||||
hexstr = hexstr.slice(0, -1);
|
hexstr = hexstr.slice(0, -1);
|
||||||
}
|
}
|
||||||
var keybuf = new Buffer(hexstr, "hex");
|
var keybuf = Buffer.from(hexstr, "hex");
|
||||||
this.write(keybuf);
|
this.write(keybuf);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -287,7 +292,9 @@ TermSession.prototype.close = function () {
|
||||||
|
|
||||||
TermSession.prototype.destroy = function () {
|
TermSession.prototype.destroy = function () {
|
||||||
var tag = this.tag();
|
var tag = this.tag();
|
||||||
fs.unlink(this.lock);
|
fs.unlink(this.lock, function (err) {
|
||||||
|
if (err) tslog("Lock removal failed: %s", err);
|
||||||
|
});
|
||||||
this.record.end();
|
this.record.end();
|
||||||
var watchsocks = this.watchers;
|
var watchsocks = this.watchers;
|
||||||
this.watchers = [];
|
this.watchers = [];
|
||||||
|
|
@ -356,7 +363,7 @@ DglSession.prototype.startchunk = function () {
|
||||||
if (this.reading)
|
if (this.reading)
|
||||||
return;
|
return;
|
||||||
this.reading = true;
|
this.reading = true;
|
||||||
var header = new Buffer(12);
|
var header = Buffer.alloc(12);
|
||||||
fs.read(this.fd, header, 0, 12, this.rpos, this.datachunk.bind(this));
|
fs.read(this.fd, header, 0, 12, this.rpos, this.datachunk.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -377,7 +384,7 @@ DglSession.prototype.datachunk = function (err, n, buf) {
|
||||||
// Something is probably wrong...
|
// Something is probably wrong...
|
||||||
tslog("DGL %s: looking for %d bytes", this.tag(), datalen);
|
tslog("DGL %s: looking for %d bytes", this.tag(), datalen);
|
||||||
}
|
}
|
||||||
var databuf = new Buffer(datalen);
|
var databuf = Buffer.alloc(datalen);
|
||||||
fs.read(this.fd, databuf, 0, datalen, this.rpos, this.handledata.bind(this));
|
fs.read(this.fd, databuf, 0, datalen, this.rpos, this.handledata.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -394,9 +401,9 @@ DglSession.prototype.handledata = function (err, n, buf) {
|
||||||
/* Process the data */
|
/* Process the data */
|
||||||
this.framepush(buf);
|
this.framepush(buf);
|
||||||
var wmsg = JSON.stringify({"t": "d", "d": buf.toString("hex")});
|
var wmsg = JSON.stringify({"t": "d", "d": buf.toString("hex")});
|
||||||
for (var i = 0; i < this.watchers.length; i++) {
|
for (let watcher of this.watchers) {
|
||||||
if (this.watchers[i].connected)
|
if (watcher.connected)
|
||||||
this.watchers[i].sendUTF(wmsg);
|
watcher.sendUTF(wmsg);
|
||||||
}
|
}
|
||||||
this.emit("data", buf);
|
this.emit("data", buf);
|
||||||
/* Recurse. */
|
/* Recurse. */
|
||||||
|
|
@ -411,7 +418,9 @@ DglSession.prototype.notifier = function (ev, finame) {
|
||||||
};
|
};
|
||||||
|
|
||||||
DglSession.prototype.close = function () {
|
DglSession.prototype.close = function () {
|
||||||
this.recwatcher.close();
|
/* The watcher might not be open yet. */
|
||||||
|
if ("recwatcher" in this)
|
||||||
|
this.recwatcher.close();
|
||||||
/* Ensure all data is handled before quitting. */
|
/* Ensure all data is handled before quitting. */
|
||||||
this.startchunk();
|
this.startchunk();
|
||||||
var connlist = this.watchers;
|
var connlist = this.watchers;
|
||||||
|
|
@ -420,7 +429,9 @@ DglSession.prototype.close = function () {
|
||||||
if (connlist[i].connected)
|
if (connlist[i].connected)
|
||||||
connlist[i].close();
|
connlist[i].close();
|
||||||
}
|
}
|
||||||
fs.close(this.fd);
|
fs.close(this.fd, function (err) {
|
||||||
|
if (err) tslog("PTY close failed: %s", err);
|
||||||
|
});
|
||||||
this.emit("close");
|
this.emit("close");
|
||||||
gamemux.emit('end', this.gname, this.pname);
|
gamemux.emit('end', this.gname, this.pname);
|
||||||
tslog("DGL %s: closed", this.tag());
|
tslog("DGL %s: closed", this.tag());
|
||||||
|
|
@ -487,8 +498,11 @@ function checksaved(user, game, callback, args) {
|
||||||
var savedirc = game.uname + "save";
|
var savedirc = game.uname + "save";
|
||||||
var basename = String(pwent.uid) + "-" + user + game.suffix;
|
var basename = String(pwent.uid) + "-" + user + game.suffix;
|
||||||
var savefile = path.join("/var/games/roguelike", savedirc, basename);
|
var savefile = path.join("/var/games/roguelike", savedirc, basename);
|
||||||
fs.exists(savefile, function (exist) {
|
fs.access(savefile, function (err) {
|
||||||
args.unshift(exist);
|
if (err)
|
||||||
|
args.unshift(false);
|
||||||
|
else
|
||||||
|
args.unshift(true);
|
||||||
callback.apply(null, args);
|
callback.apply(null, args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -567,8 +581,8 @@ function bufncmp(buf1, buf2, n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isclear(buf) {
|
function isclear(buf) {
|
||||||
for (var i = 0; i < clearbufs.length; i++) {
|
for (let clearer of clearbufs) {
|
||||||
if (bufncmp(buf, clearbufs[i], clearbufs[i].length))
|
if (bufncmp(buf, clearer, clearer.length))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -688,10 +702,15 @@ function login(req, res, formdata) {
|
||||||
function regsetup(username) {
|
function regsetup(username) {
|
||||||
function regsetup_l2(err) {
|
function regsetup_l2(err) {
|
||||||
for (var g in games) {
|
for (var g in games) {
|
||||||
fs.mkdir(path.join("/dgldir/ttyrec", username, games[g].uname), 0755);
|
fs.mkdir(path.join("/dgldir/ttyrec", username, games[g].uname), 0755,
|
||||||
|
function (err) {
|
||||||
|
if (err) tslog("ttyrec mkdir failed: %s", err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fs.mkdir(path.join("/dgldir/userdata", username), 0755);
|
fs.mkdir(path.join("/dgldir/userdata", username), 0755, function (err) {
|
||||||
|
if (err) tslog("Userdata mkdir failed: %s", err);
|
||||||
|
});
|
||||||
fs.mkdir(path.join("/dgldir/ttyrec/", username), 0755, regsetup_l2);
|
fs.mkdir(path.join("/dgldir/ttyrec/", username), 0755, regsetup_l2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -779,7 +798,9 @@ function stopgame(res, formdata) {
|
||||||
if (err.code == "ESRCH") {
|
if (err.code == "ESRCH") {
|
||||||
var nodere = RegExp("^" + pname + ":node:");
|
var nodere = RegExp("^" + pname + ":node:");
|
||||||
if (fname.match(nodere)) {
|
if (fname.match(nodere)) {
|
||||||
fs.unlink(fullfile);
|
fs.unlink(fullfile, function (err) {
|
||||||
|
if (err) tslog("Stale lock removal failed: %s", err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -832,6 +853,8 @@ function startProgressWatcher() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function serveStatic(req, res, fname) {
|
function serveStatic(req, res, fname) {
|
||||||
|
if (fname[0] !== "/")
|
||||||
|
fname = "/" + fname;
|
||||||
var nname = path.normalize(fname);
|
var nname = path.normalize(fname);
|
||||||
if (nname == "" || nname == "/")
|
if (nname == "" || nname == "/")
|
||||||
nname = "index.html";
|
nname = "index.html";
|
||||||
|
|
@ -839,9 +862,9 @@ function serveStatic(req, res, fname) {
|
||||||
path.join(nname, "index.html"); /* it was a directory */
|
path.join(nname, "index.html"); /* it was a directory */
|
||||||
var realname = path.join(rlgwebd_options.static_root, nname);
|
var realname = path.join(rlgwebd_options.static_root, nname);
|
||||||
var extension = path.extname(realname);
|
var extension = path.extname(realname);
|
||||||
fs.exists(realname, function (exists) {
|
fs.access(realname, function (access_err) {
|
||||||
var resheaders = {};
|
var resheaders = {};
|
||||||
if (!exists || !extension || extension == ".html")
|
if (access_err || !extension || extension == ".html")
|
||||||
resheaders["Content-Type"] = "text/html; charset=utf-8";
|
resheaders["Content-Type"] = "text/html; charset=utf-8";
|
||||||
else if (extension == ".png")
|
else if (extension == ".png")
|
||||||
resheaders["Content-Type"] = "image/png";
|
resheaders["Content-Type"] = "image/png";
|
||||||
|
|
@ -853,7 +876,7 @@ function serveStatic(req, res, fname) {
|
||||||
resheaders["Content-Type"] = "image/svg+xml";
|
resheaders["Content-Type"] = "image/svg+xml";
|
||||||
else
|
else
|
||||||
resheaders["Content-Type"] = "application/octet-stream";
|
resheaders["Content-Type"] = "application/octet-stream";
|
||||||
if (exists) {
|
if (!access_err) {
|
||||||
fs.readFile(realname, function (error, data) {
|
fs.readFile(realname, function (error, data) {
|
||||||
if (error) {
|
if (error) {
|
||||||
res.writeHead(500, {});
|
res.writeHead(500, {});
|
||||||
|
|
@ -1024,10 +1047,6 @@ function setuinfo(req, res, postdata) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var errorcodes = [ "Generic Error", "Not logged in", "Invalid data",
|
|
||||||
"Login failed", "Already playing", "Game launch failed",
|
|
||||||
"Server shutting down", "Game not in progress" ];
|
|
||||||
|
|
||||||
function sendError(res, ecode, msg, box) {
|
function sendError(res, ecode, msg, box) {
|
||||||
res.writeHead(200, { "Content-Type": "application/json" });
|
res.writeHead(200, { "Content-Type": "application/json" });
|
||||||
var edict = {"t": "E"};
|
var edict = {"t": "E"};
|
||||||
|
|
@ -1264,6 +1283,21 @@ if (rlgwebd_options.use_https) {
|
||||||
tls_options.ca = read_or_die(rlgwebd_options.cafile, "CA file");
|
tls_options.ca = read_or_die(rlgwebd_options.cafile, "CA file");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Make sure the socket directory is secure. */
|
||||||
|
var socket_dir = path.dirname(rlgwebd_options.control_socket);
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(socket_dir, 0o700);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err.code == "EEXIST") {
|
||||||
|
fs.chownSync(socket_dir, 0, 0);
|
||||||
|
fs.chmodSync(socket_dir, 0o700);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Open the control socket before chrooting where it can't be found */
|
/* Open the control socket before chrooting where it can't be found */
|
||||||
var ctlServer = net.createServer(function (sock) {
|
var ctlServer = net.createServer(function (sock) {
|
||||||
sock.on('data', consoleHandler);
|
sock.on('data', consoleHandler);
|
||||||
|
|
@ -1288,20 +1322,22 @@ ctlServer.listen(rlgwebd_options.control_socket, function () {
|
||||||
tslog("Could not drop permissions: %s", err);
|
tslog("Could not drop permissions: %s", err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
httpServer = http.createServer(webHandler);
|
|
||||||
httpServer.listen(rlgwebd_options.http_port);
|
|
||||||
tslog('rlgwebd running on port %d', rlgwebd_options.http_port);
|
|
||||||
wsServer = new WebSocketServer({"httpServer": httpServer});
|
|
||||||
wsServer.on("request", wsHandler);
|
|
||||||
tslog('WebSockets are online');
|
|
||||||
if (rlgwebd_options.use_https) {
|
if (rlgwebd_options.use_https) {
|
||||||
var httpsServer = https.createServer(tls_options, webHandler);
|
httpServer = https.createServer(tls_options, webHandler);
|
||||||
httpsServer.listen(rlgwebd_options.https_port);
|
httpServer.listen(rlgwebd_options.port);
|
||||||
tslog('TLS running on port %d', rlgwebd_options.https_port);
|
tslog('rlgwebd running on port %d (TLS)', rlgwebd_options.port);
|
||||||
var wssServer = new WebSocketServer({"httpServer": httpsServer});
|
wsServer = new WebSocketServer({"httpServer": httpServer});
|
||||||
wssServer.on("request", wsHandler);
|
wsServer.on("request", wsHandler);
|
||||||
tslog('Secure WebSockets are online');
|
tslog('Secure WebSockets are online');
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
httpServer = http.createServer(webHandler);
|
||||||
|
httpServer.listen(rlgwebd_options.port);
|
||||||
|
tslog('rlgwebd running on port %d', rlgwebd_options.port);
|
||||||
|
wsServer = new WebSocketServer({"httpServer": httpServer});
|
||||||
|
wsServer.on("request", wsHandler);
|
||||||
|
tslog('WebSockets are online');
|
||||||
|
}
|
||||||
progressWatcher = startProgressWatcher();
|
progressWatcher = startProgressWatcher();
|
||||||
setInterval(pushStatus, 40000);
|
setInterval(pushStatus, 40000);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
19
rlgwebd-stop
19
rlgwebd-stop
|
|
@ -1,22 +1,19 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
var domain = require('domain');
|
var sockpath = "/var/run/rlgwebd/rlgwebd.sock";
|
||||||
var sockpath = "/var/run/rlgwebd.sock";
|
|
||||||
|
|
||||||
var dom = domain.create();
|
var sock = new net.Socket();
|
||||||
|
|
||||||
dom.on('error', function (err) {
|
sock.on('error', function (err) {
|
||||||
console.log("Cannot connect to " + sockpath + ", rlgwebd already stopped.");
|
console.log("Cannot connect to " + sockpath + ", rlgwebd already stopped.");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
dom.run(function () {
|
sock.connect(sockpath, function () {
|
||||||
var sock = net.connect(sockpath, function () {
|
sock.on('close', function (had_error) {
|
||||||
sock.on('close', function () {
|
if (process.argv[2] == "debug")
|
||||||
if (process.argv[2] == "debug")
|
console.log("Control socket closed");
|
||||||
console.log("Control socket closed");
|
|
||||||
});
|
|
||||||
sock.write("quit\n");
|
|
||||||
});
|
});
|
||||||
|
sock.write("quit\n");
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@
|
||||||
|
|
||||||
# These values are set by default:
|
# These values are set by default:
|
||||||
# Location of the socket for start/stop commands
|
# Location of the socket for start/stop commands
|
||||||
#control_socket = /var/run/rlgwebd.sock
|
#control_socket = /var/run/rlgwebd/rlgwebd.sock
|
||||||
# Port number to bind
|
# Port number to bind
|
||||||
#http_port = 8080
|
#port = 8080
|
||||||
# Port number for HTTPS
|
|
||||||
#https_port = 8081
|
|
||||||
# Path to the dgamelaunch installation to chroot into
|
# Path to the dgamelaunch installation to chroot into
|
||||||
# If you change this, change the Makefile too
|
# If you change this, change the Makefile too
|
||||||
#chrootDir = /var/dgl/
|
#chrootDir = /var/dgl/
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ After=network.target syslog.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
Environment=NODE_PATH=/usr/lib/node_modules
|
Environment=NODE_PATH=/var/local/lib/node_modules
|
||||||
ExecStart=/usr/local/bin/rlgwebd
|
ExecStart=/usr/local/bin/rlgwebd
|
||||||
ExecStop=/usr/local/bin/rlgwebd-stop
|
ExecStop=/usr/local/bin/rlgwebd-stop
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
|
|
|
||||||
196
termemu.js
196
termemu.js
|
|
@ -71,6 +71,7 @@ var termemu = {
|
||||||
scrB: 0, // init() will set this properly
|
scrB: 0, // init() will set this properly
|
||||||
c: null, // Contains cursor position and text attributes
|
c: null, // Contains cursor position and text attributes
|
||||||
offedge: false, // Going off the edge doesn't mean adding a new line
|
offedge: false, // Going off the edge doesn't mean adding a new line
|
||||||
|
lastcode: 0, // Last printed character
|
||||||
clearAttrs: function () {
|
clearAttrs: function () {
|
||||||
/* Make sure to reset ALL attribute properties and NOTHING else. */
|
/* Make sure to reset ALL attribute properties and NOTHING else. */
|
||||||
this.c.bold = false;
|
this.c.bold = false;
|
||||||
|
|
@ -460,6 +461,7 @@ var termemu = {
|
||||||
this.screen.replaceChild(this.makeRow(), this.screen.childNodes[i]);
|
this.screen.replaceChild(this.makeRow(), this.screen.childNodes[i]);
|
||||||
}
|
}
|
||||||
this.flipCursor(); // make it appear in the new row
|
this.flipCursor(); // make it appear in the new row
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
write: function (codes) {
|
write: function (codes) {
|
||||||
|
|
@ -531,6 +533,10 @@ var termemu = {
|
||||||
debug(1, "Unrecognized sequence ESC " + codes[i].toString(16));
|
debug(1, "Unrecognized sequence ESC " + codes[i].toString(16));
|
||||||
this.comseq = [];
|
this.comseq = [];
|
||||||
}
|
}
|
||||||
|
if (this.comseq.length == 0) {
|
||||||
|
// A complete sequence was processed, clear lastcode.
|
||||||
|
this.lastcode = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (this.comseq.length == 2 && this.comseq[0] == 27) {
|
else if (this.comseq.length == 2 && this.comseq[0] == 27) {
|
||||||
/* An ESC C N sequence. Not implemented. Doesn't check validity
|
/* An ESC C N sequence. Not implemented. Doesn't check validity
|
||||||
|
|
@ -555,6 +561,7 @@ var termemu = {
|
||||||
String.fromCharCode(this.comseq[1]) + " 0x" +
|
String.fromCharCode(this.comseq[1]) + " 0x" +
|
||||||
codes[i].toString(16));
|
codes[i].toString(16));
|
||||||
this.comseq = [];
|
this.comseq = [];
|
||||||
|
this.lastcode = 0;
|
||||||
}
|
}
|
||||||
else if (this.comseq[0] == 157) {
|
else if (this.comseq[0] == 157) {
|
||||||
/* Commands beginning with OSC */
|
/* Commands beginning with OSC */
|
||||||
|
|
@ -566,6 +573,7 @@ var termemu = {
|
||||||
debug(0, "Got " + (this.comseq.length - 1) + "-byte OSC sequence");
|
debug(0, "Got " + (this.comseq.length - 1) + "-byte OSC sequence");
|
||||||
this.oscProcess();
|
this.oscProcess();
|
||||||
this.comseq = [];
|
this.comseq = [];
|
||||||
|
this.lastcode = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.comseq.push(codes[i]);
|
this.comseq.push(codes[i]);
|
||||||
|
|
@ -582,15 +590,17 @@ var termemu = {
|
||||||
/* Chars in csiPre can only occur right after the CSI */
|
/* Chars in csiPre can only occur right after the CSI */
|
||||||
debug(1, "Invalid CSI sequence: misplaced prefix");
|
debug(1, "Invalid CSI sequence: misplaced prefix");
|
||||||
this.comseq = [];
|
this.comseq = [];
|
||||||
|
this.lastcode = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.comseq.push(codes[i]);
|
this.comseq.push(codes[i]);
|
||||||
}
|
}
|
||||||
else if (csiPost.indexOf(this.comseq[this.comseq.length - 1]) >= 0 &&
|
else if (csiPost.indexOf(this.comseq[this.comseq.length - 1]) >= 0 &&
|
||||||
!csiFinal(codes[i])) {
|
!csiFinal(codes[i])) {
|
||||||
/* Chars is csiPost must come right before the final char */
|
/* Chars in csiPost must come right before the final char */
|
||||||
debug(1, "Invalid CSI sequence: misplaced postfix");
|
debug(1, "Invalid CSI sequence: misplaced postfix");
|
||||||
this.comseq = [];
|
this.comseq = [];
|
||||||
|
this.lastcode = 0;
|
||||||
}
|
}
|
||||||
else if ((codes[i] >= 48 && codes[i] <= 57) || codes[i] == 59 ||
|
else if ((codes[i] >= 48 && codes[i] <= 57) || codes[i] == 59 ||
|
||||||
csiPost.indexOf(codes[i]) >= 0) {
|
csiPost.indexOf(codes[i]) >= 0) {
|
||||||
|
|
@ -605,91 +615,102 @@ var termemu = {
|
||||||
else {
|
else {
|
||||||
debug(1, "Invalid CSI sequence: unknown code " + codes[i].toString(16));
|
debug(1, "Invalid CSI sequence: unknown code " + codes[i].toString(16));
|
||||||
this.comseq = [];
|
this.comseq = [];
|
||||||
|
this.lastcode = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
debug(1, "Unknown sequence with " + this.comseq[0].toString(16));
|
debug(1, "Unknown sequence with " + this.comseq[0].toString(16));
|
||||||
this.comseq = [];
|
this.comseq = [];
|
||||||
}
|
this.lastcode = 0;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Treat it as a single character. */
|
|
||||||
if (codes[i] == 5) {
|
|
||||||
sendback("06");
|
|
||||||
}
|
|
||||||
else if (codes[i] == 7) {
|
|
||||||
/* bell */
|
|
||||||
bell(true);
|
|
||||||
}
|
|
||||||
else if (codes[i] == 8) {
|
|
||||||
/* backspace */
|
|
||||||
if (this.offedge)
|
|
||||||
this.offedge = false;
|
|
||||||
else if (this.c.x > 0)
|
|
||||||
this.cmove(null, this.c.x - 1);
|
|
||||||
}
|
|
||||||
else if (codes[i] == 9) {
|
|
||||||
/* tab */
|
|
||||||
var xnew;
|
|
||||||
if (this.c.x < this.w - 1) {
|
|
||||||
xnew = 8 * (Math.floor(this.c.x / 8) + 1);
|
|
||||||
if (xnew >= this.w)
|
|
||||||
xnew = this.w - 1;
|
|
||||||
this.cmove(null, xnew);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.offedge = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (codes[i] >= 10 && codes[i] <= 12) {
|
else if ((codes[i] >= 32 && codes[i] < 127) || codes[i] >= 160) {
|
||||||
/* newline, vertical tab, form feed */
|
|
||||||
if (this.offedge)
|
|
||||||
this.newline(true);
|
|
||||||
else
|
|
||||||
this.newline(false);
|
|
||||||
}
|
|
||||||
else if (codes[i] == 13) {
|
|
||||||
/* carriage return \r */
|
|
||||||
this.cmove(null, 0);
|
|
||||||
}
|
|
||||||
else if (codes[i] == 14) {
|
|
||||||
/* shift out */
|
|
||||||
// Currently assuming that G1 is DEC Special & Line Drawing
|
|
||||||
this.c.cset = "0";
|
|
||||||
debug(0, "Using DEC graphics charset.");
|
|
||||||
}
|
|
||||||
else if (codes[i] == 15) {
|
|
||||||
/* shift in */
|
|
||||||
// Currently assuming that G0 is ASCII
|
|
||||||
this.c.cset = "B";
|
|
||||||
debug(0, "Using ASCII charset.");
|
|
||||||
}
|
|
||||||
else if (codes[i] == 27) {
|
|
||||||
/* escape */
|
|
||||||
this.comseq.push(codes[i]);
|
|
||||||
}
|
|
||||||
else if (codes[i] < 32 || (codes[i] >= 127 && codes[i] < 160)) {
|
|
||||||
/* Some kind of control character. */
|
|
||||||
debug(1, "Unprintable character 0x" + codes[i].toString(16));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* If it's ASCII, it's printable; take a risk on anything higher */
|
/* If it's ASCII, it's printable; take a risk on anything higher */
|
||||||
if ((this.c.cset == "0") && (codes[i] in decChars)) {
|
if ((this.c.cset == "0") && (codes[i] in decChars)) {
|
||||||
// DEC special character set
|
// DEC special character set
|
||||||
this.placechar(String.fromCharCode(decChars[codes[i]]));
|
this.lastcode = decChars[codes[i]];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.placechar(String.fromCharCode(codes[i]));
|
this.lastcode = codes[i];
|
||||||
}
|
}
|
||||||
|
this.placechar(String.fromCharCode(this.lastcode));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Treat it as a single control character. */
|
||||||
|
this.singleCtl(codes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
|
singleCtl: function (ctlcode) {
|
||||||
|
if (ctlcode == 5) {
|
||||||
|
sendback("06");
|
||||||
|
}
|
||||||
|
else if (ctlcode == 7) {
|
||||||
|
/* bell */
|
||||||
|
bell(true);
|
||||||
|
}
|
||||||
|
else if (ctlcode == 8) {
|
||||||
|
/* backspace */
|
||||||
|
if (this.offedge)
|
||||||
|
this.offedge = false;
|
||||||
|
else if (this.c.x > 0)
|
||||||
|
this.cmove(null, this.c.x - 1);
|
||||||
|
}
|
||||||
|
else if (ctlcode == 9) {
|
||||||
|
/* tab */
|
||||||
|
var xnew;
|
||||||
|
if (this.c.x < this.w - 1) {
|
||||||
|
xnew = 8 * (Math.floor(this.c.x / 8) + 1);
|
||||||
|
if (xnew >= this.w)
|
||||||
|
xnew = this.w - 1;
|
||||||
|
this.cmove(null, xnew);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.offedge = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ctlcode >= 10 && ctlcode <= 12) {
|
||||||
|
/* newline, vertical tab, form feed */
|
||||||
|
if (this.offedge)
|
||||||
|
this.newline(true);
|
||||||
|
else
|
||||||
|
this.newline(false);
|
||||||
|
}
|
||||||
|
else if (ctlcode == 13) {
|
||||||
|
/* carriage return \r */
|
||||||
|
this.cmove(null, 0);
|
||||||
|
}
|
||||||
|
else if (ctlcode == 14) {
|
||||||
|
/* shift out */
|
||||||
|
// Currently assuming that G1 is DEC Special & Line Drawing
|
||||||
|
this.c.cset = "0";
|
||||||
|
debug(0, "Using DEC graphics charset.");
|
||||||
|
}
|
||||||
|
else if (ctlcode == 15) {
|
||||||
|
/* shift in */
|
||||||
|
// Currently assuming that G0 is ASCII
|
||||||
|
this.c.cset = "B";
|
||||||
|
debug(0, "Using ASCII charset.");
|
||||||
|
}
|
||||||
|
else if (ctlcode == 27) {
|
||||||
|
/* escape */
|
||||||
|
this.comseq.push(27);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug(1, "Unprintable character 0x" + ctlcode.toString(16));
|
||||||
|
}
|
||||||
|
if (ctlcode != 27) {
|
||||||
|
// Sequences should preserve lastcode until they are completed
|
||||||
|
this.lastcode = 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
csiProcess: function () {
|
csiProcess: function () {
|
||||||
/* Processes the CSI sequence in this.comseq */
|
/* Processes the CSI sequence in this.comseq */
|
||||||
var c = this.comseq[this.comseq.length - 1];
|
var c = this.comseq[this.comseq.length - 1];
|
||||||
if (this.comseq[0] != 155 || !csiFinal(c))
|
if (this.comseq[0] != 155 || !csiFinal(c))
|
||||||
return;
|
return;
|
||||||
|
var printed = false;
|
||||||
var comstr = "";
|
var comstr = "";
|
||||||
for (var i = 1; i < this.comseq.length; i++)
|
for (var i = 1; i < this.comseq.length; i++)
|
||||||
comstr += String.fromCharCode(this.comseq[i]);
|
comstr += String.fromCharCode(this.comseq[i]);
|
||||||
|
|
@ -698,6 +719,7 @@ var termemu = {
|
||||||
var matchCSI = comstr.match(reCSI);
|
var matchCSI = comstr.match(reCSI);
|
||||||
if (!matchCSI) {
|
if (!matchCSI) {
|
||||||
debug(1, "Unrecognized CSI sequence: " + comstr);
|
debug(1, "Unrecognized CSI sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var prefix = null;
|
var prefix = null;
|
||||||
|
|
@ -725,6 +747,7 @@ var termemu = {
|
||||||
/* @ - insert spaces at cursor */
|
/* @ - insert spaces at cursor */
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI @ sequence: " + comstr);
|
debug(1, "Invalid CSI @ sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* The cursor stays still, but characters move out from under it. */
|
/* The cursor stays still, but characters move out from under it. */
|
||||||
|
|
@ -745,6 +768,7 @@ var termemu = {
|
||||||
/* E - next line, F - previous line, G - to column */
|
/* E - next line, F - previous line, G - to column */
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI sequence: " + comstr);
|
debug(1, "Invalid CSI sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* These may be out of range, but cmove will take care of that. */
|
/* These may be out of range, but cmove will take care of that. */
|
||||||
|
|
@ -769,6 +793,7 @@ var termemu = {
|
||||||
var y = 0;
|
var y = 0;
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI H sequence: " + comstr);
|
debug(1, "Invalid CSI H sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (params[0])
|
if (params[0])
|
||||||
|
|
@ -787,6 +812,7 @@ var termemu = {
|
||||||
var x = this.c.x;
|
var x = this.c.x;
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI I sequence: " + comstr);
|
debug(1, "Invalid CSI I sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
|
|
@ -808,6 +834,7 @@ var termemu = {
|
||||||
debug(1, "Warning: CSI ?J not implemented");
|
debug(1, "Warning: CSI ?J not implemented");
|
||||||
else if (prefix || postfix) {
|
else if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI J sequence: " + comstr);
|
debug(1, "Invalid CSI J sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!params[0]) {
|
if (!params[0]) {
|
||||||
|
|
@ -828,6 +855,7 @@ var termemu = {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
debug(1, "Unimplemented parameter in CSI J sequence: " + comstr);
|
debug(1, "Unimplemented parameter in CSI J sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (var nrow = start; nrow <= end; nrow++) {
|
for (var nrow = start; nrow <= end; nrow++) {
|
||||||
|
|
@ -855,6 +883,7 @@ var termemu = {
|
||||||
debug(1, "Warning: CSI ?K not implemented");
|
debug(1, "Warning: CSI ?K not implemented");
|
||||||
else if (prefix || postfix) {
|
else if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI K sequence: " + comstr);
|
debug(1, "Invalid CSI K sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* 0 (default): right, 1: left, 2: all. Include cursor position. */
|
/* 0 (default): right, 1: left, 2: all. Include cursor position. */
|
||||||
|
|
@ -885,11 +914,14 @@ var termemu = {
|
||||||
* M - delete current lines */
|
* M - delete current lines */
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI sequence: " + comstr);
|
debug(1, "Invalid CSI sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* CSI LM have no effect outside of the scrolling region */
|
/* CSI LM have no effect outside of the scrolling region */
|
||||||
if (this.c.y < this.scrT || this.c.y > this.scrB)
|
if (this.c.y < this.scrT || this.c.y > this.scrB) {
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
this.flipCursor();
|
this.flipCursor();
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
var blankrow = this.makeRow();
|
var blankrow = this.makeRow();
|
||||||
|
|
@ -915,6 +947,7 @@ var termemu = {
|
||||||
/* P - delete at active position, causing cells on the right to shift. */
|
/* P - delete at active position, causing cells on the right to shift. */
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI P sequence: " + comstr);
|
debug(1, "Invalid CSI P sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var cursrow = this.screen.childNodes[this.c.y];
|
var cursrow = this.screen.childNodes[this.c.y];
|
||||||
|
|
@ -930,6 +963,7 @@ var termemu = {
|
||||||
/* S - scroll up, T - scroll down */
|
/* S - scroll up, T - scroll down */
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI sequence: " + comstr);
|
debug(1, "Invalid CSI sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (c == 83)
|
if (c == 83)
|
||||||
|
|
@ -941,6 +975,7 @@ var termemu = {
|
||||||
/* X - erase characters */
|
/* X - erase characters */
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI sequence: " + comstr);
|
debug(1, "Invalid CSI sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var row = this.screen.childNodes[this.c.y];
|
var row = this.screen.childNodes[this.c.y];
|
||||||
|
|
@ -954,6 +989,7 @@ var termemu = {
|
||||||
var x = this.c.x;
|
var x = this.c.x;
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI Z sequence: " + comstr);
|
debug(1, "Invalid CSI Z sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
|
|
@ -970,14 +1006,26 @@ var termemu = {
|
||||||
/* ` - go to col */
|
/* ` - go to col */
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI ` sequence: " + comstr);
|
debug(1, "Invalid CSI ` sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.cmove(null, count - 1);
|
this.cmove(null, count - 1);
|
||||||
}
|
}
|
||||||
|
else if (c == 98) {
|
||||||
|
/* b - repeat previous character */
|
||||||
|
if (this.lastcode !== 0) {
|
||||||
|
while (count > 0) {
|
||||||
|
this.placechar(String.fromCharCode(this.lastcode));
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
printed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (c == 99) {
|
else if (c == 99) {
|
||||||
/* c - query terminal attributes */
|
/* c - query terminal attributes */
|
||||||
if (prefix !== null) {
|
if (prefix !== null) {
|
||||||
debug(1, "Unimplemented CSI sequence: " + comstr);
|
debug(1, "Unimplemented CSI sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* "CSI ? 1 ; 2 c" - VT100 */
|
/* "CSI ? 1 ; 2 c" - VT100 */
|
||||||
|
|
@ -987,6 +1035,7 @@ var termemu = {
|
||||||
/* d - go to row */
|
/* d - go to row */
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI d sequence: " + comstr);
|
debug(1, "Invalid CSI d sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.cmove(count - 1, null);
|
this.cmove(count - 1, null);
|
||||||
|
|
@ -997,6 +1046,7 @@ var termemu = {
|
||||||
var y = 0;
|
var y = 0;
|
||||||
if (prefix || postfix) {
|
if (prefix || postfix) {
|
||||||
debug(1, "Invalid CSI f sequence: " + comstr);
|
debug(1, "Invalid CSI f sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (params[0])
|
if (params[0])
|
||||||
|
|
@ -1009,6 +1059,7 @@ var termemu = {
|
||||||
/* h - set modes */
|
/* h - set modes */
|
||||||
if (prefix != '?') {
|
if (prefix != '?') {
|
||||||
debug(1, "Unimplemented CSI sequence: " + comstr);
|
debug(1, "Unimplemented CSI sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (var i = 0; i < params.length; i++) {
|
for (var i = 0; i < params.length; i++) {
|
||||||
|
|
@ -1047,6 +1098,7 @@ var termemu = {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
debug(1, "Unimplemented CSI sequence: " + comstr);
|
debug(1, "Unimplemented CSI sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1080,6 +1132,7 @@ var termemu = {
|
||||||
/* m - character attributes */
|
/* m - character attributes */
|
||||||
if (prefix !== null) {
|
if (prefix !== null) {
|
||||||
debug(1, "Unimplemented CSI sequence: " + comstr);
|
debug(1, "Unimplemented CSI sequence: " + comstr);
|
||||||
|
this.lastcode = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (params.length == 0)
|
if (params.length == 0)
|
||||||
|
|
@ -1133,15 +1186,18 @@ var termemu = {
|
||||||
t = params[0] - 1;
|
t = params[0] - 1;
|
||||||
if (params[1] && params[1] <= this.h)
|
if (params[1] && params[1] <= this.h)
|
||||||
b = params[1] - 1;
|
b = params[1] - 1;
|
||||||
if (b <= t)
|
if (b > t) {
|
||||||
return;
|
this.scrT = t;
|
||||||
this.scrT = t;
|
this.scrB = b;
|
||||||
this.scrB = b;
|
this.cmove(0, 0);
|
||||||
this.cmove(0, 0);
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
debug(1, "Unimplemented CSI sequence: " + comstr);
|
debug(1, "Unimplemented CSI sequence: " + comstr);
|
||||||
}
|
}
|
||||||
|
if (!printed) {
|
||||||
|
this.lastcode = 0;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
oscProcess: function () {
|
oscProcess: function () {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue