Error counters in MyServer panel, Autobackup now default, new console msg support.

This commit is contained in:
Ylian Saint-Hilaire 2019-05-20 16:00:33 -07:00
parent 576b079545
commit 96a65a6c3e
11 changed files with 205 additions and 117 deletions

View File

@ -813,6 +813,9 @@ function createMeshCore(agent) {
return;
}
// Test the console messaging system
//this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'This is a sample test for remote terminal...' })); // Send a console message back using the console channel, "\n" is supported.
// Perform notification if needed. Toast messages may not be supported on all platforms.
if (this.httprequest.consent && (this.httprequest.consent & 2)) {
try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote terminal session.'); } catch (ex) { }
@ -860,8 +863,8 @@ function createMeshCore(agent) {
this.on('data', onTunnelControlData);
//this.write('MeshCore Terminal Hello');
if (process.platform == 'linux') { this.httprequest.process.stdin.write("stty erase ^H\nalias ls='ls --color=auto'\nclear\n"); }
} else if (this.httprequest.protocol == 2)
{
} else if (this.httprequest.protocol == 2) {
// Check user access rights for desktop
if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) {
// Disengage this tunnel, user does not have the rights to do this!!
@ -871,6 +874,9 @@ function createMeshCore(agent) {
return;
}
// Test the console messaging system
//this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'This is a sample test for remote desktop...' })); // Send a console message back using the console channel, "\n" is supported.
// Perform notification if needed. Toast messages may not be supported on all platforms.
if (this.httprequest.consent && (this.httprequest.consent & 1)) {
try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote desktop session.'); } catch (ex) { }
@ -916,7 +922,9 @@ function createMeshCore(agent) {
this.removeAllListeners('data');
this.on('data', onTunnelControlData);
//this.write('MeshCore KVM Hello!1');
} else if (this.httprequest.protocol == 5) {
// Check user access rights for files
if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0))) {
// Disengage this tunnel, user does not have the rights to do this!!
@ -926,6 +934,9 @@ function createMeshCore(agent) {
return;
}
// Test the console messaging system
//this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'This is a sample test for remote files...' })); // Send a console message back using the console channel, "\n" is supported.
// Perform notification if needed
if (this.httprequest.consent && (this.httprequest.consent & 4)) {
try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote file access.'); } catch (ex) { }

File diff suppressed because one or more lines are too long

125
db.js
View File

@ -670,29 +670,52 @@ module.exports.CreateDB = function (parent, func) {
obj.performingBackup = false;
obj.performBackup = function () {
if (obj.performingBackup) return 1;
obj.performingBackup = true;
//console.log('Performing backup...');
try { obj.parent.fs.mkdirSync(obj.parent.backuppath); } catch (e) { }
const dbname = (obj.parent.args.mongodbname) ? (obj.parent.args.mongodbname) : 'meshcentral';
const currentDate = new Date();
const fileSuffix = currentDate.getFullYear() + '-' + padNumber(currentDate.getMonth() + 1, 2) + '-' + padNumber(currentDate.getDate(), 2) + '-' + padNumber(currentDate.getHours(), 2) + '-' + padNumber(currentDate.getMinutes(), 2);
const newAutoBackupFile = 'meshcentral-autobackup-' + fileSuffix;
const newAutoBackupPath = obj.parent.path.join(obj.parent.backuppath, newAutoBackupFile);
try {
if (obj.performingBackup) return 1;
obj.performingBackup = true;
//console.log('Performing backup...');
try { obj.parent.fs.mkdirSync(obj.parent.backuppath); } catch (e) { }
const dbname = (obj.parent.args.mongodbname) ? (obj.parent.args.mongodbname) : 'meshcentral';
const currentDate = new Date();
const fileSuffix = currentDate.getFullYear() + '-' + padNumber(currentDate.getMonth() + 1, 2) + '-' + padNumber(currentDate.getDate(), 2) + '-' + padNumber(currentDate.getHours(), 2) + '-' + padNumber(currentDate.getMinutes(), 2);
const newAutoBackupFile = 'meshcentral-autobackup-' + fileSuffix;
const newAutoBackupPath = obj.parent.path.join(obj.parent.backuppath, newAutoBackupFile);
if ((obj.databaseType == 2) || (obj.databaseType == 3)) {
// Perform a MongoDump backup
const newBackupFile = 'mongodump-' + fileSuffix;
const newBackupPath = obj.parent.path.join(obj.parent.backuppath, newBackupFile);
var mongoDumpPath = 'mongodump';
if (obj.parent.config.settings.autobackup && obj.parent.config.settings.autobackup.mongodumppath) { mongoDumpPath = obj.parent.config.settings.autobackup.mongodumppath; }
const child_process = require('child_process');
const cmd = mongoDumpPath + ' --db \"' + dbname + '\" --archive=\"' + newBackupPath + '.archive\"';
var backupProcess = child_process.exec(cmd, { cwd: obj.parent.backuppath }, function (error, stdout, stderr) {
backupProcess = null;
if ((error != null) && (error != '')) { console.log('ERROR: Unable to perform database backup.\r\n'); obj.performingBackup = false; return; }
if ((obj.databaseType == 2) || (obj.databaseType == 3)) {
// Perform a MongoDump backup
const newBackupFile = 'mongodump-' + fileSuffix;
const newBackupPath = obj.parent.path.join(obj.parent.backuppath, newBackupFile);
var mongoDumpPath = 'mongodump';
if (obj.parent.config.settings.autobackup && obj.parent.config.settings.autobackup.mongodumppath) { mongoDumpPath = obj.parent.config.settings.autobackup.mongodumppath; }
const child_process = require('child_process');
const cmd = mongoDumpPath + ' --db \"' + dbname + '\" --archive=\"' + newBackupPath + '.archive\"';
var backupProcess = child_process.exec(cmd, { cwd: obj.parent.backuppath }, function (error, stdout, stderr) {
try {
backupProcess = null;
if ((error != null) && (error != '')) { console.log('ERROR: Unable to perform database backup.\r\n'); obj.performingBackup = false; return; }
// Perform archive compression
// Perform archive compression
var archiver = require('archiver');
var output = obj.parent.fs.createWriteStream(newAutoBackupPath + '.zip');
var archive = null;
if (obj.parent.config.settings.autobackup && (typeof obj.parent.config.settings.autobackup.zippassword == 'string')) {
try { archiver.registerFormat('zip-encrypted', require("archiver-zip-encrypted")); } catch (ex) { }
archive = archiver.create('zip-encrypted', { zlib: { level: 9 }, encryptionMethod: 'aes256', password: obj.parent.config.settings.autobackup.zippassword });
} else {
archive = archiver('zip', { zlib: { level: 9 } });
}
output.on('close', function () { obj.performingBackup = false; setTimeout(function () { try { obj.parent.fs.unlink(newBackupPath + '.archive', function () { }); } catch (ex) { console.log(ex); } }, 5000); });
output.on('end', function () { });
archive.on('warning', function (err) { console.log('Backup warning: ' + err); });
archive.on('error', function (err) { console.log('Backup error: ' + err); });
archive.pipe(output);
archive.file(newBackupPath + '.archive', { name: newBackupFile + '.archive' });
archive.directory(obj.parent.datapath, 'meshcentral-data');
archive.finalize();
} catch (ex) { console.log(ex); }
});
} else {
// Perform a NeDB backup
var archiver = require('archiver');
var output = obj.parent.fs.createWriteStream(newAutoBackupPath + '.zip');
var archive = null;
@ -702,55 +725,37 @@ module.exports.CreateDB = function (parent, func) {
} else {
archive = archiver('zip', { zlib: { level: 9 } });
}
output.on('close', function () { obj.performingBackup = false; setTimeout(function () { try { obj.parent.fs.unlink(newBackupPath + '.archive', function () { }); } catch (ex) { console.log(ex); } }, 5000); });
output.on('close', function () { obj.performingBackup = false; });
output.on('end', function () { });
archive.on('warning', function (err) { console.log('Backup warning: ' + err); });
archive.on('error', function (err) { console.log('Backup error: ' + err); });
archive.pipe(output);
archive.file(newBackupPath + '.archive', { name: newBackupFile + '.archive' });
archive.directory(obj.parent.datapath, 'meshcentral-data');
archive.finalize();
});
} else {
// Perform a NeDB backup
var archiver = require('archiver');
var output = obj.parent.fs.createWriteStream(newAutoBackupPath + '.zip');
var archive = null;
if (obj.parent.config.settings.autobackup && (typeof obj.parent.config.settings.autobackup.zippassword == 'string')) {
try { archiver.registerFormat('zip-encrypted', require("archiver-zip-encrypted")); } catch (ex) { }
archive = archiver.create('zip-encrypted', { zlib: { level: 9 }, encryptionMethod: 'aes256', password: obj.parent.config.settings.autobackup.zippassword });
} else {
archive = archiver('zip', { zlib: { level: 9 } });
}
output.on('close', function () { obj.performingBackup = false; });
output.on('end', function () { });
archive.on('warning', function (err) { console.log('Backup warning: ' + err); });
archive.on('error', function (err) { console.log('Backup error: ' + err); });
archive.pipe(output);
archive.directory(obj.parent.datapath, 'meshcentral-data');
archive.finalize();
}
// Remove old backups
if (obj.parent.config.settings.autobackup && (typeof obj.parent.config.settings.autobackup.keeplastdaysbackup == 'number')) {
var cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - obj.parent.config.settings.autobackup.keeplastdaysbackup);
obj.parent.fs.readdir(obj.parent.backuppath, function (err, dir) {
if ((err == null) && (dir.length > 0)) {
for (var i in dir) {
var name = dir[i];
if (name.startsWith('meshcentral-autobackup-') && name.endsWith('.zip')) {
var timex = name.substring(23, name.length - 4).split('-');
if (timex.length == 5) {
var fileDate = new Date(parseInt(timex[0]), parseInt(timex[1]) - 1, parseInt(timex[2]), parseInt(timex[3]), parseInt(timex[4]));
if (fileDate && (cutoffDate > fileDate)) { try { obj.parent.fs.unlink(obj.parent.path.join(obj.parent.backuppath, name), function () { }); } catch (ex) { } }
// Remove old backups
if (obj.parent.config.settings.autobackup && (typeof obj.parent.config.settings.autobackup.keeplastdaysbackup == 'number')) {
var cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - obj.parent.config.settings.autobackup.keeplastdaysbackup);
obj.parent.fs.readdir(obj.parent.backuppath, function (err, dir) {
try {
if ((err == null) && (dir.length > 0)) {
for (var i in dir) {
var name = dir[i];
if (name.startsWith('meshcentral-autobackup-') && name.endsWith('.zip')) {
var timex = name.substring(23, name.length - 4).split('-');
if (timex.length == 5) {
var fileDate = new Date(parseInt(timex[0]), parseInt(timex[1]) - 1, parseInt(timex[2]), parseInt(timex[3]), parseInt(timex[4]));
if (fileDate && (cutoffDate > fileDate)) { try { obj.parent.fs.unlink(obj.parent.path.join(obj.parent.backuppath, name), function () { }); } catch (ex) { } }
}
}
}
}
}
}
});
}
} catch (ex) { console.log(ex); }
});
}
} catch (ex) { console.log(ex); }
return 0;
}

View File

@ -868,7 +868,11 @@ function CreateMeshCentralServer(config, args) {
if (obj.args.nousers == true) { obj.updateServerState('nousers', '1'); }
obj.updateServerState('state', 'running');
// Setup database backup
// Setup auto-backup defaults
if (obj.config.settings.autobackup == null) { obj.config.settings.autobackup = { backupinvervalhours: 24, keeplastdaysbackup: 10 }; }
else if (obj.config.settings.autobackup === false) { delete obj.config.settings.autobackup; }
// Setup auto-backup timer
if (obj.config.settings.autobackup && (typeof obj.config.settings.autobackup.backupinvervalhours == 'number')) {
setInterval(obj.db.performBackup, obj.config.settings.autobackup.backupinvervalhours * 60 * 60 * 1000);
}

View File

@ -232,6 +232,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Send current server statistics
obj.SendServerStats = function () {
// Take a look at server stats
var os = require('os');
var stats = { action: 'serverstats', totalmem: os.totalmem(), freemem: os.freemem() };
if (parent.parent.platform != 'win32') { stats.cpuavg = os.loadavg(); } // else { stats.cpuavg = [ 0.2435345, 0.523234234, 0.6435345345 ]; }
@ -246,7 +247,28 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
};
if (parent.relaySessionErrorCount != 0) { serverStats['Relay Errors'] = parent.relaySessionErrorCount; }
if (parent.parent.mpsserver != null) { serverStats['Connected Intel® AMT'] = Object.keys(parent.parent.mpsserver.ciraConnections).length; }
// Take a look at agent errors
var agentstats = parent.getAgentStats();
var errorCounters = {}, errorCountersCount = 0;
if (agentstats.meshDoesNotExistCount > 0) { errorCountersCount++; errorCounters["Unknown Group"] = agentstats.meshDoesNotExistCount; }
if (agentstats.invalidPkcsSignatureCount > 0) { errorCountersCount++; errorCounters["Invalid PKCS signature"] = agentstats.invalidPkcsSignatureCount; }
if (agentstats.invalidRsaSignatureCount > 0) { errorCountersCount++; errorCounters["Invalid RSA siguature"] = agentstats.invalidRsaSignatureCount; }
if (agentstats.invalidJsonCount > 0) { errorCountersCount++; errorCounters["Invalid JSON"] = agentstats.invalidJsonCount; }
if (agentstats.unknownAgentActionCount > 0) { errorCountersCount++; errorCounters["Unknown Action"] = agentstats.unknownAgentActionCount; }
if (agentstats.agentBadWebCertHashCount > 0) { errorCountersCount++; errorCounters["Bad Web Certificate"] = agentstats.agentBadWebCertHashCount; }
if (agentstats.agentBadSignature1Count > 0) { errorCountersCount++; errorCounters["Bad Signature (1)"] = agentstats.agentBadSignature1Count; }
if (agentstats.agentBadSignature2Count > 0) { errorCountersCount++; errorCounters["Bad Signature (2)"] = agentstats.agentBadSignature2Count; }
if (agentstats.agentMaxSessionHoldCount > 0) { errorCountersCount++; errorCounters["Max Sessions Reached"] = agentstats.agentMaxSessionHoldCount; }
if (agentstats.invalidDomainMeshCount > 0) { errorCountersCount++; errorCounters["Invalid Domain"] = agentstats.invalidDomainMeshCount; }
if (agentstats.invalidMeshTypeCount > 0) { errorCountersCount++; errorCounters["Invalid Group Type (1)"] = agentstats.invalidMeshTypeCount; }
if (agentstats.invalidDomainMesh2Count > 0) { errorCountersCount++; errorCounters["Invalid Group"] = agentstats.invalidDomainMesh2Count; }
if (agentstats.invalidMeshType2Count > 0) { errorCountersCount++; errorCounters["Invalid Group Type (2)"] = agentstats.invalidMeshType2Count; }
if (agentstats.duplicateAgentCount > 0) { errorCountersCount++; errorCounters["Duplicate Agent"] = agentstats.duplicateAgentCount; }
// Send out the stats
stats.values = { "Server State": serverStats }
if (errorCountersCount > 0) { stats.values["Agent Error Counters"] = errorCounters; }
try { ws.send(JSON.stringify(stats)); } catch (ex) { }
}

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.3.4-s",
"version": "0.3.4-t",
"keywords": [
"Remote Management",
"Intel AMT",

View File

@ -258,7 +258,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
if (disp == 65535) { displays[disp] = 'All Displays'; } else { displays[disp] = 'Display ' + disp; }
}
}
console.log('Get Displays', displays, selectedDisplay, rstr2hex(str));
//console.log('Get Displays', displays, selectedDisplay, rstr2hex(str));
if (obj.onDisplayinfo != null) { obj.onDisplayinfo(obj, displays, selectedDisplay); }
break;
case 12: // SetDisplay
@ -283,7 +283,13 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
break;
case 65: // Alert
str = str.substring(4);
if (str[0] != '.') { console.log(str); alert('KVM: ' + str); } else { console.log('KVM: ' + str.substring(1)); }
if (str[0] != '.') {
console.log(str); //alert('KVM: ' + str);
obj.parent.consoleMessage = str;
if (obj.parent.onConsoleMessageChange) { obj.parent.onConsoleMessageChange(obj.parent, str); }
} else {
console.log('KVM: ' + str.substring(1));
}
break;
}
return cmdsize + jumboAdd;

View File

@ -26,6 +26,10 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au
obj.webrtc = null;
obj.debugmode = 0;
// Console Message
obj.consoleMessage = null;
obj.onConsoleMessageChange = null;
// Private method
//obj.debug = function (msg) { console.log(msg); }
@ -59,7 +63,10 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au
try { controlMsg = JSON.parse(msg); } catch (e) { return; }
if (controlMsg.ctrlChannel != '102938') { obj.xxOnSocketData(msg); return; }
//console.log(controlMsg);
if (obj.webrtc != null) {
if (controlMsg.type == 'console') {
obj.consoleMessage = controlMsg.msg;
if (obj.onConsoleMessageChange) { obj.onConsoleMessageChange(obj, obj.consoleMessage); }
} else if (obj.webrtc != null) {
if (controlMsg.type == 'answer') {
obj.webrtc.setRemoteDescription(new RTCSessionDescription(controlMsg), function () { /*console.log('WebRTC remote ok');*/ }, obj.xxCloseWebRTC);
} else if (controlMsg.type == 'webrtc0') {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -468,6 +468,7 @@
<div id="DeskToolsProcesses" style=""></div>
</div>
</div>
<div id=p11DeskConsoleMsg style="display:none;cursor:pointer;position:absolute;right:30px;bottom:30px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p11clearConsoleMsg()></div>
</div>
<div id=deskarea4 class="areaFoot">
<div class="toright2">
@ -508,53 +509,56 @@
<div class="icon2"></div>
<div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
</div>
<table id=termTable cellpadding=0 cellspacing=0>
<tr>
<td class="areaHead">
<div class="toright2">
<input id="termActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction()/>
</div>
<div>
<input type="button" id="autoconnectbutton2" value="AutoConnect" onclick=autoConnectTerminal(event) onkeypress="return false" onkeydown="return false" style="display:none">
<span id="connectbutton2span"><input type="button" id="connectbutton2" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
<span id="connectbutton2hspan">&nbsp;<input type="button" id="connectbutton2h" value="HW Connect" onclick=connectTerminal(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
<span id="disconnectbutton2span">&nbsp;<input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false"></span>
&nbsp;<span id="termstatus">Disconnected</span>
</div>
</td>
</tr>
<tr>
<td>
<div class="areaProgress"><div id="termprogressbar" style=""></div></div>
</td>
</tr>
<tr>
<td id="termarea3x">
<pre id="Term"></pre>
</td>
</tr>
<tr>
<td class="areaFoot">
<div class="toright2">
<span id="terminalSettingsButtons" style="display:none">
<input id="id_tcrbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="CR+LF" title="Toggle what the return key will send" onclick="termToggleCr()">
<input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx()">
<input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()">
</span>
<select id="specialkeylist" onkeypress="return false"></select>
<input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />
</div>
<div>
&nbsp;
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Backspace" onclick="termSendKey(8,'bsbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()" />
</div>
</td>
</tr>
</table>
<div id=termTable style="position:relative">
<table style="width:100%" cellpadding=0 cellspacing=0>
<tr>
<td class="areaHead">
<div class="toright2">
<input id="termActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction()/>
</div>
<div>
<input type="button" id="autoconnectbutton2" value="AutoConnect" onclick=autoConnectTerminal(event) onkeypress="return false" onkeydown="return false" style="display:none">
<span id="connectbutton2span"><input type="button" id="connectbutton2" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
<span id="connectbutton2hspan">&nbsp;<input type="button" id="connectbutton2h" value="HW Connect" onclick=connectTerminal(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
<span id="disconnectbutton2span">&nbsp;<input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false"></span>
&nbsp;<span id="termstatus">Disconnected</span>
</div>
</td>
</tr>
<tr>
<td>
<div class="areaProgress"><div id="termprogressbar" style=""></div></div>
</td>
</tr>
<tr>
<td id="termarea3x">
<pre id="Term"></pre>
</td>
</tr>
<tr>
<td class="areaFoot">
<div class="toright2">
<span id="terminalSettingsButtons" style="display:none">
<input id="id_tcrbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="CR+LF" title="Toggle what the return key will send" onclick="termToggleCr()">
<input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx()">
<input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()">
</span>
<select id="specialkeylist" onkeypress="return false"></select>
<input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />
</div>
<div>
&nbsp;
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Backspace" onclick="termSendKey(8,'bsbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()" />
</div>
</td>
</tr>
</table>
<div id=p12TermConsoleMsg style="display:none;cursor:pointer;position:absolute;right:30px;bottom:45px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p12clearConsoleMsg()></div>
</div>
</div>
<div id=p13 style="display:none">
<div id="p13title">
@ -607,6 +611,7 @@
</td>
</tr>
</table>
<div id=p13FilesConsoleMsg style="display:none;cursor:pointer;position:absolute;right:30px;bottom:55px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p13clearConsoleMsg()></div>
<div id="p13filetable" style="">
<div id="p13bigok" style="display:none"><b>&checkmark;</b></div>
<div id="p13bigfail" style="display:none"><b>&#10007;</b></div>
@ -931,6 +936,11 @@
var webPageFullScreen = true;
var nightMode = (getstore('_nightMode', '0') == '1');
// Console Message Display Timers
var p11DeskConsoleMsgTimer = null;
var p12TermConsoleMsgTimer = null;
var p13FilesConsoleMsgTimer = null;
function startup() {
if ((features & 32) == 0) {
// Guard against other site's top frames (web bugs).
@ -2479,6 +2489,7 @@
desk.shortid = shortid;
desk.attemptWebRTC = attemptWebRTC;
desk.onStateChanged = onMultiDesktopStateChange;
//desk.onConsoleMessageChange = function () { console.log('CONSOLEMSG:', desk.consoleMessage); }
desk.m.CompressionLevel = multidesktopsettings.quality;
desk.m.ScalingLevel = multidesktopsettings.scaling;
desk.m.FrameRateTimer = multidesktopsettings.framerate;
@ -4458,6 +4469,12 @@
desktop.m.debugmode = debugmode;
desktop.attemptWebRTC = attemptWebRTC;
desktop.onStateChanged = onDesktopStateChange;
desktop.onConsoleMessageChange = function () {
p11clearConsoleMsg();
QH('p11DeskConsoleMsg', EscapeHtml(desktop.consoleMessage).split('\n').join('<br />'));
QV('p11DeskConsoleMsg', true);
p11DeskConsoleMsgTimer = setTimeout(p11clearConsoleMsg, 8000);
}
desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
desktop.m.ScalingLevel = desktopsettings.scaling;
desktop.m.FrameRateTimer = desktopsettings.framerate;
@ -4474,6 +4491,10 @@
}
}
function p11clearConsoleMsg() { QV('p11DeskConsoleMsg', false); if (p11DeskConsoleMsgTimer) { clearTimeout(p11DeskConsoleMsgTimer); p11DeskConsoleMsgTimer = null; } }
function p12clearConsoleMsg() { QV('p12TermConsoleMsg', false); if (p12TermConsoleMsgTimer) { clearTimeout(p12TermConsoleMsgTimer); p12TermConsoleMsgTimer = null; } }
function p13clearConsoleMsg() { QV('p13FilesConsoleMsg', false); if (p13FilesConsoleMsgTimer) { clearTimeout(p13FilesConsoleMsgTimer); p13FilesConsoleMsgTimer = null; } }
var webRtcDesktop = null;
function webRtcDesktopReset() {
if (webRtcDesktop == null) return;
@ -4946,6 +4967,12 @@
terminal.m.lineFeed = ([1, 2, 3, 4, 21, 22].indexOf(currentNode.agent.id) >= 0) ? '\r\n' : '\r'; // On windows, send \r\n, on Linux only \r
terminal.attemptWebRTC = attemptWebRTC;
terminal.onStateChanged = onTerminalStateChange;
terminal.onConsoleMessageChange = function () {
p12clearConsoleMsg();
QH('p12TermConsoleMsg', EscapeHtml(terminal.consoleMessage).split('\n').join('<br />'));
QV('p12TermConsoleMsg', true);
p12TermConsoleMsgTimer = setTimeout(p12clearConsoleMsg, 8000);
}
terminal.Start(terminalNode._id);
terminal.contype = 1;
terminal.m.terminalEmulation = 0;
@ -5065,6 +5092,12 @@
files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie);
files.attemptWebRTC = attemptWebRTC;
files.onStateChanged = onFilesStateChange;
files.onConsoleMessageChange = function () {
p13clearConsoleMsg();
QH('p13FilesConsoleMsg', EscapeHtml(files.consoleMessage).split('\n').join('<br />'));
QV('p13FilesConsoleMsg', true);
p13FilesConsoleMsgTimer = setTimeout(p13clearConsoleMsg, 8000);
}
files.Start(filesNode._id);
} else {
//QH('Term', '');