mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-02-12 11:01:52 +00:00
Added remote process control
This commit is contained in:
parent
d05f086a0e
commit
fb55e44edf
14 changed files with 448 additions and 47 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -30,6 +30,7 @@ function createMeshCore(agent) {
|
|||
var net = require('net');
|
||||
var fs = require('fs');
|
||||
var rtc = require('ILibWebRTC');
|
||||
var processManager = require('process-manager');
|
||||
var SMBiosTables = require('smbios');
|
||||
var amtMei = null, amtLms = null, amtLmsState = 0;
|
||||
var amtMeiConnected = 0, amtMeiTmpState = null;
|
||||
|
@ -327,13 +328,16 @@ function createMeshCore(agent) {
|
|||
// If this is a console command, parse it and call the console handler
|
||||
switch (data.action) {
|
||||
case 'msg': {
|
||||
if (data.type == 'console') { // Process a console command
|
||||
switch (data.type) {
|
||||
case 'console': { // Process a console command
|
||||
if (data.value && data.sessionid) {
|
||||
var args = splitArgs(data.value);
|
||||
processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if ((data.type == 'tunnel') && (data.value != null)) { // Process a new tunnel connection request
|
||||
case 'tunnel': {
|
||||
if (data.value != null) { // Process a new tunnel connection request
|
||||
// Create a new tunnel object
|
||||
var xurl = getServerTargetUrlEx(data.value);
|
||||
if (xurl != null) {
|
||||
|
@ -361,6 +365,19 @@ function createMeshCore(agent) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'ps': {
|
||||
if (data.sessionid) {
|
||||
processManager.getProcesses(function (plist) { mesh.SendCommand({ "action": "msg", "type": "ps", "value": JSON.stringify(plist), "sessionid": data.sessionid }); });
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'pskill': {
|
||||
sendConsoleText(JSON.stringify(data));
|
||||
try { process.kill(data.value); } catch (e) { sendConsoleText(JSON.stringify(e)); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
case 'wakeonlan': {
|
||||
// Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
|
||||
sendConsoleText('Server requesting wake-on-lan for: ' + data.macs.join(', '));
|
||||
|
@ -819,7 +836,7 @@ function createMeshCore(agent) {
|
|||
var response = null;
|
||||
switch (cmd) {
|
||||
case 'help': { // Displays available commands
|
||||
response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios.';
|
||||
response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, ps, kill, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios.';
|
||||
break;
|
||||
}
|
||||
case 'setdebug': {
|
||||
|
@ -827,6 +844,23 @@ function createMeshCore(agent) {
|
|||
else { if (args['_'][0] == '*') { console.setDestination(1); } else { console.setDestination(parseInt(args['_'][0]), sessionid); } }
|
||||
break;
|
||||
}
|
||||
case 'ps': {
|
||||
processManager.getProcesses(function (plist) {
|
||||
var x = '';
|
||||
for (var i in plist) { x += i + ', ' + plist[i].cmd + ((plist[i].user) ? (', ' + plist[i].user):'') + '\r\n'; }
|
||||
sendConsoleText(x, sessionid);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'kill': {
|
||||
if ((args['_'].length < 1)) {
|
||||
response = 'Proper usage: kill [pid]'; // Display correct command usage
|
||||
} else {
|
||||
process.kill(parseInt(args['_'][0]));
|
||||
response = 'Killed process ' + args['_'][0] + '.';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'smbios': {
|
||||
if (SMBiosTables != null) {
|
||||
SMBiosTables.get(function (data) {
|
||||
|
|
102
agents/modules_meshcmd/UserSessions.js
Normal file
102
agents/modules_meshcmd/UserSessions.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
|
||||
|
||||
function UserSessions()
|
||||
{
|
||||
this._ObjectID = 'UserSessions';
|
||||
|
||||
if (process.platform == 'win32') {
|
||||
this._marshal = require('_GenericMarshal');
|
||||
this._kernel32 = this._marshal.CreateNativeProxy('Kernel32.dll');
|
||||
this._kernel32.CreateMethod('GetLastError');
|
||||
this._wts = this._marshal.CreateNativeProxy('Wtsapi32.dll');
|
||||
this._wts.CreateMethod('WTSEnumerateSessionsA');
|
||||
this._wts.CreateMethod('WTSQuerySessionInformationA');
|
||||
this._wts.CreateMethod('WTSFreeMemory');
|
||||
this.SessionStates = ['Active', 'Connected', 'ConnectQuery', 'Shadow', 'Disconnected', 'Idle', 'Listening', 'Reset', 'Down', 'Init'];
|
||||
this.InfoClass =
|
||||
{
|
||||
'WTSInitialProgram': 0,
|
||||
'WTSApplicationName': 1,
|
||||
'WTSWorkingDirectory': 2,
|
||||
'WTSOEMId': 3,
|
||||
'WTSSessionId': 4,
|
||||
'WTSUserName': 5,
|
||||
'WTSWinStationName': 6,
|
||||
'WTSDomainName': 7,
|
||||
'WTSConnectState': 8,
|
||||
'WTSClientBuildNumber': 9,
|
||||
'WTSClientName': 10,
|
||||
'WTSClientDirectory': 11,
|
||||
'WTSClientProductId': 12,
|
||||
'WTSClientHardwareId': 13,
|
||||
'WTSClientAddress': 14,
|
||||
'WTSClientDisplay': 15,
|
||||
'WTSClientProtocolType': 16,
|
||||
'WTSIdleTime': 17,
|
||||
'WTSLogonTime': 18,
|
||||
'WTSIncomingBytes': 19,
|
||||
'WTSOutgoingBytes': 20,
|
||||
'WTSIncomingFrames': 21,
|
||||
'WTSOutgoingFrames': 22,
|
||||
'WTSClientInfo': 23,
|
||||
'WTSSessionInfo': 24,
|
||||
'WTSSessionInfoEx': 25,
|
||||
'WTSConfigInfo': 26,
|
||||
'WTSValidationInfo': 27,
|
||||
'WTSSessionAddressV4': 28,
|
||||
'WTSIsRemoteSession': 29
|
||||
};
|
||||
|
||||
this.getSessionAttribute = function getSessionAttribute(sessionId, attr)
|
||||
{
|
||||
var buffer = this._marshal.CreatePointer();
|
||||
var bytesReturned = this._marshal.CreateVariable(4);
|
||||
|
||||
if (this._wts.WTSQuerySessionInformationA(0, sessionId, attr, buffer, bytesReturned).Val == 0)
|
||||
{
|
||||
throw ('Error calling WTSQuerySessionInformation: ' + this._kernel32.GetLastError.Val);
|
||||
}
|
||||
|
||||
var retVal = buffer.Deref().String;
|
||||
|
||||
this._wts.WTSFreeMemory(buffer.Deref());
|
||||
return (retVal);
|
||||
};
|
||||
|
||||
this.Current = function Current()
|
||||
{
|
||||
var retVal = {};
|
||||
var pinfo = this._marshal.CreatePointer();
|
||||
var count = this._marshal.CreateVariable(4);
|
||||
if (this._wts.WTSEnumerateSessionsA(0, 0, 1, pinfo, count).Val == 0)
|
||||
{
|
||||
throw ('Error calling WTSEnumerateSessionsA: ' + this._kernel32.GetLastError().Val);
|
||||
}
|
||||
|
||||
for (var i = 0; i < count.toBuffer().readUInt32LE() ; ++i)
|
||||
{
|
||||
var info = pinfo.Deref().Deref(i * (this._marshal.PointerSize == 4 ? 12 : 24), this._marshal.PointerSize == 4 ? 12 : 24);
|
||||
var j = { SessionId: info.toBuffer().readUInt32LE() };
|
||||
j.StationName = info.Deref(this._marshal.PointerSize == 4 ? 4 : 8, this._marshal.PointerSize).Deref().String;
|
||||
j.State = this.SessionStates[info.Deref(this._marshal.PointerSize == 4 ? 8 : 16, 4).toBuffer().readUInt32LE()];
|
||||
if (j.State == 'Active') {
|
||||
j.Username = this.getSessionAttribute(j.SessionId, this.InfoClass.WTSUserName);
|
||||
j.Domain = this.getSessionAttribute(j.SessionId, this.InfoClass.WTSDomainName);
|
||||
}
|
||||
retVal[j.SessionId] = j;
|
||||
}
|
||||
|
||||
this._wts.WTSFreeMemory(pinfo.Deref());
|
||||
return (retVal);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Current = function Current()
|
||||
{
|
||||
return ({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new UserSessions();
|
102
agents/modules_meshcore/UserSessions.js
Normal file
102
agents/modules_meshcore/UserSessions.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
|
||||
|
||||
function UserSessions()
|
||||
{
|
||||
this._ObjectID = 'UserSessions';
|
||||
|
||||
if (process.platform == 'win32') {
|
||||
this._marshal = require('_GenericMarshal');
|
||||
this._kernel32 = this._marshal.CreateNativeProxy('Kernel32.dll');
|
||||
this._kernel32.CreateMethod('GetLastError');
|
||||
this._wts = this._marshal.CreateNativeProxy('Wtsapi32.dll');
|
||||
this._wts.CreateMethod('WTSEnumerateSessionsA');
|
||||
this._wts.CreateMethod('WTSQuerySessionInformationA');
|
||||
this._wts.CreateMethod('WTSFreeMemory');
|
||||
this.SessionStates = ['Active', 'Connected', 'ConnectQuery', 'Shadow', 'Disconnected', 'Idle', 'Listening', 'Reset', 'Down', 'Init'];
|
||||
this.InfoClass =
|
||||
{
|
||||
'WTSInitialProgram': 0,
|
||||
'WTSApplicationName': 1,
|
||||
'WTSWorkingDirectory': 2,
|
||||
'WTSOEMId': 3,
|
||||
'WTSSessionId': 4,
|
||||
'WTSUserName': 5,
|
||||
'WTSWinStationName': 6,
|
||||
'WTSDomainName': 7,
|
||||
'WTSConnectState': 8,
|
||||
'WTSClientBuildNumber': 9,
|
||||
'WTSClientName': 10,
|
||||
'WTSClientDirectory': 11,
|
||||
'WTSClientProductId': 12,
|
||||
'WTSClientHardwareId': 13,
|
||||
'WTSClientAddress': 14,
|
||||
'WTSClientDisplay': 15,
|
||||
'WTSClientProtocolType': 16,
|
||||
'WTSIdleTime': 17,
|
||||
'WTSLogonTime': 18,
|
||||
'WTSIncomingBytes': 19,
|
||||
'WTSOutgoingBytes': 20,
|
||||
'WTSIncomingFrames': 21,
|
||||
'WTSOutgoingFrames': 22,
|
||||
'WTSClientInfo': 23,
|
||||
'WTSSessionInfo': 24,
|
||||
'WTSSessionInfoEx': 25,
|
||||
'WTSConfigInfo': 26,
|
||||
'WTSValidationInfo': 27,
|
||||
'WTSSessionAddressV4': 28,
|
||||
'WTSIsRemoteSession': 29
|
||||
};
|
||||
|
||||
this.getSessionAttribute = function getSessionAttribute(sessionId, attr)
|
||||
{
|
||||
var buffer = this._marshal.CreatePointer();
|
||||
var bytesReturned = this._marshal.CreateVariable(4);
|
||||
|
||||
if (this._wts.WTSQuerySessionInformationA(0, sessionId, attr, buffer, bytesReturned).Val == 0)
|
||||
{
|
||||
throw ('Error calling WTSQuerySessionInformation: ' + this._kernel32.GetLastError.Val);
|
||||
}
|
||||
|
||||
var retVal = buffer.Deref().String;
|
||||
|
||||
this._wts.WTSFreeMemory(buffer.Deref());
|
||||
return (retVal);
|
||||
};
|
||||
|
||||
this.Current = function Current()
|
||||
{
|
||||
var retVal = {};
|
||||
var pinfo = this._marshal.CreatePointer();
|
||||
var count = this._marshal.CreateVariable(4);
|
||||
if (this._wts.WTSEnumerateSessionsA(0, 0, 1, pinfo, count).Val == 0)
|
||||
{
|
||||
throw ('Error calling WTSEnumerateSessionsA: ' + this._kernel32.GetLastError().Val);
|
||||
}
|
||||
|
||||
for (var i = 0; i < count.toBuffer().readUInt32LE() ; ++i)
|
||||
{
|
||||
var info = pinfo.Deref().Deref(i * (this._marshal.PointerSize == 4 ? 12 : 24), this._marshal.PointerSize == 4 ? 12 : 24);
|
||||
var j = { SessionId: info.toBuffer().readUInt32LE() };
|
||||
j.StationName = info.Deref(this._marshal.PointerSize == 4 ? 4 : 8, this._marshal.PointerSize).Deref().String;
|
||||
j.State = this.SessionStates[info.Deref(this._marshal.PointerSize == 4 ? 8 : 16, 4).toBuffer().readUInt32LE()];
|
||||
if (j.State == 'Active') {
|
||||
j.Username = this.getSessionAttribute(j.SessionId, this.InfoClass.WTSUserName);
|
||||
j.Domain = this.getSessionAttribute(j.SessionId, this.InfoClass.WTSDomainName);
|
||||
}
|
||||
retVal[j.SessionId] = j;
|
||||
}
|
||||
|
||||
this._wts.WTSFreeMemory(pinfo.Deref());
|
||||
return (retVal);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Current = function Current()
|
||||
{
|
||||
return ({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new UserSessions();
|
96
agents/modules_meshcore/process-manager.js
Normal file
96
agents/modules_meshcore/process-manager.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
var GM = require('_GenericMarshal');
|
||||
|
||||
function processManager() {
|
||||
this._ObjectID = 'processManager';
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
this._kernel32 = GM.CreateNativeProxy('kernel32.dll');
|
||||
this._kernel32.CreateMethod('GetLastError');
|
||||
this._kernel32.CreateMethod('CreateToolhelp32Snapshot');
|
||||
this._kernel32.CreateMethod('Process32First');
|
||||
this._kernel32.CreateMethod('Process32Next');
|
||||
break;
|
||||
case 'linux':
|
||||
this._childProcess = require('child_process');
|
||||
break;
|
||||
default:
|
||||
throw (process.platform + ' not supported');
|
||||
}
|
||||
this.getProcesses = function getProcesses(callback) {
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
var h = this._kernel32.CreateToolhelp32Snapshot(2, 0), info = GM.CreateVariable(304), retVal = {};
|
||||
info.toBuffer().writeUInt32LE(304, 0);
|
||||
var nextProcess = this._kernel32.Process32First(h, info);
|
||||
while (nextProcess.Val) {
|
||||
retVal[info.Deref(8, 4).toBuffer().readUInt32LE(0)] = { cmd: info.Deref(GM.PointerSize == 4 ? 36 : 44, 260).String };
|
||||
nextProcess = this._kernel32.Process32Next(h, info);
|
||||
}
|
||||
if (callback) { callback.apply(this, [retVal]); }
|
||||
break;
|
||||
case 'linux':
|
||||
if (!this._psp) { this._psp = {}; }
|
||||
var p = this._childProcess.execFile("/bin/ps", ["ps", "-uxa"], { type: this._childProcess.SpawnTypes.TERM });
|
||||
this._psp[p.pid] = p;
|
||||
p.Parent = this;
|
||||
p.ps = '';
|
||||
p.callback = callback;
|
||||
p.args = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { p.args.push(arguments[i]); }
|
||||
p.on('exit', function onGetProcesses() {
|
||||
delete this.Parent._psp[this.pid];
|
||||
var retVal = {}, lines = this.ps.split('\x0D\x0A'), key = {}, keyi = 0;
|
||||
for (var i in lines) {
|
||||
var tokens = lines[i].split(' '), tokenList = [];
|
||||
for (var x in tokens) {
|
||||
if (i == 0 && tokens[x]) { key[tokens[x]] = keyi++; }
|
||||
if (i > 0 && tokens[x]) { tokenList.push(tokens[x]); }
|
||||
}
|
||||
if ((i > 0) && (tokenList[key.PID])) {
|
||||
retVal[tokenList[key.PID]] = { user: tokenList[key.USER], cmd: tokenList[key.COMMAND] };
|
||||
}
|
||||
}
|
||||
if (this.callback) {
|
||||
this.args.unshift(retVal);
|
||||
this.callback.apply(this.parent, this.args);
|
||||
}
|
||||
});
|
||||
p.stdout.on('data', function (chunk) { this.parent.ps += chunk.toString(); });
|
||||
break;
|
||||
default:
|
||||
throw ('Enumerating processes on ' + process.platform + ' not supported');
|
||||
}
|
||||
};
|
||||
this.getProcessInfo = function getProcessInfo(pid) {
|
||||
switch (process.platform) {
|
||||
case 'linux':
|
||||
var status = require('fs').readFileSync('/proc/' + pid + '/status'), lines = status.toString().split('\n'), info = {};
|
||||
for (var i in lines) {
|
||||
var tokens = lines[i].split(':');
|
||||
if (tokens.length > 1) { tokens[1] = tokens[1].trim(); }
|
||||
info[tokens[0]] = tokens[1];
|
||||
}
|
||||
return info;
|
||||
default:
|
||||
throw ('getProcessInfo() not supported for ' + process.platform);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = new processManager();
|
|
@ -651,9 +651,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
|||
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
|
||||
if (obj.common.validateString(command.devicename, 1, 256) == false) break; // Check device name
|
||||
if (obj.common.validateString(command.hostname, 1, 256) == false) break; // Check hostname
|
||||
if (obj.common.validateString(command.amtusername, 1, 16) == false) break; // Check username
|
||||
if (obj.common.validateString(command.amtpassword, 1, 16) == false) break; // Check password
|
||||
if (obj.common.validateInt(command.amttls, 0, 1) == false) break; // Check TLS flag
|
||||
if (obj.common.validateString(command.amtusername, 0, 16) == false) break; // Check username
|
||||
if (obj.common.validateString(command.amtpassword, 0, 16) == false) break; // Check password
|
||||
if (command.amttls == '0') { command.amttls = 0; } else if (command.amttls == '1') { command.amttls = 1; } // Check TLS flag
|
||||
if ((command.amttls != 1) && (command.amttls != 0)) break;
|
||||
|
||||
// Get the mesh
|
||||
var mesh = obj.parent.meshes[command.meshid];
|
||||
|
@ -667,7 +668,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
|
|||
obj.parent.crypto.randomBytes(48, function (err, buf) {
|
||||
// create the new node
|
||||
var nodeid = 'node/' + domain.id + '/' + buf.toString('base64').replace(/\+/g, '@').replace(/\//g, '$');;
|
||||
var device = { type: 'node', mtype: 1, _id: nodeid, meshid: command.meshid, name: command.devicename, host: command.hostname, domain: domain.id, intelamt: { user: command.amtusername, pass: command.amtpassword, tls: parseInt(command.amttls) } };
|
||||
var device = { type: 'node', mtype: 1, _id: nodeid, meshid: command.meshid, name: command.devicename, host: command.hostname, domain: domain.id, intelamt: { user: command.amtusername, pass: command.amtpassword, tls: command.amttls } };
|
||||
obj.db.Set(device);
|
||||
|
||||
// Event the new node
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.1.6-a",
|
||||
"version": "0.1.6-c",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
|
|
@ -514,3 +514,11 @@ a {
|
|||
.notification:hover {
|
||||
background-color: #EFE8B6;
|
||||
}
|
||||
|
||||
.deskToolsBar {
|
||||
padding:3px;
|
||||
}
|
||||
|
||||
.deskToolsBar:hover {
|
||||
background-color: #EFE8B6;
|
||||
}
|
|
@ -360,12 +360,21 @@
|
|||
<div id="DeskParent">
|
||||
<canvas id="Desk" width="640" height="200" style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></canvas>
|
||||
</div>
|
||||
<div id="DeskTools" style="position:absolute;width:400px;height:100%;background-color:gray;top:0;right:0;border-left:2px solid lightgray;display:none">
|
||||
<a id="DeskToolsRefreshButton" style="float:right;padding:3px;cursor:pointer" onclick="refreshDeskTools()">Refresh</a>
|
||||
<div id="DeskToolsBar" style="position:absolute;padding:3px;border-radius: 3px 3px 0px 0px;top:5px;left:4px;bottom:26px;background-color:lightgray;cursor:pointer">Processes</div>
|
||||
<div style="position:absolute;top:26px;left:4px;right:4px;bottom:4px;background-color:lightgray;text-align:left">
|
||||
<div style="border-bottom:1px solid darkgray;padding:3px"><a style=width:50px;padding-right:5px;float:left;cursor:pointer title="Sort by process id" onclick=sortProcess(0)>PID</a><a style=cursor:pointer title="Sort by name" onclick=sortProcess(1)>Name</a></div>
|
||||
<div id="DeskToolsProcesses" style="overflow-y:scroll;position:absolute;top:24px;bottom:0px;width:100%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id=deskarea4>
|
||||
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
|
||||
<div style="float:right;text-align:right">
|
||||
<select id="termdisplays" style="display:none" onchange="deskSetDisplay(event)" onclick="deskGetDisplayNumbers(event)"></select>
|
||||
<input id="DeskToolsButton" type="button" value="Tools" title="Toggle tools view" onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()">
|
||||
</div>
|
||||
<div>
|
||||
|
||||
|
@ -969,11 +978,13 @@
|
|||
if (index != -1) {
|
||||
// Node was found, dispatch the message
|
||||
if (message.type == 'console') { p15consoleReceive(nodes[index], message.value); } // This is a console message.
|
||||
if (message.type == 'notify') { // This is a notification message.
|
||||
else if (message.type == 'notify') { // This is a notification message.
|
||||
var n = { text:message.value };
|
||||
if (message.nodeid != null) { n.nodeid = message.nodeid; }
|
||||
if (message.tag != null) { n.tag = message.tag; }
|
||||
addNotification(n);
|
||||
} else if (message.type == 'ps') {
|
||||
showDeskToolsProcesses(message);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2823,6 +2834,10 @@
|
|||
|
||||
// Request the power timeline
|
||||
if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { powerTimelineReq = currentNode._id; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
|
||||
|
||||
// Reset the desktop tools
|
||||
QV('DeskTools', false);
|
||||
showDeskToolsProcesses();
|
||||
}
|
||||
setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
|
||||
if (!panel) panel = 10;
|
||||
|
@ -3168,15 +3183,16 @@
|
|||
// Show and enable the right buttons
|
||||
function updateDesktopButtons() {
|
||||
var mesh = meshes[currentNode.meshid];
|
||||
var deskState = ((desktop != null) && (desktop.state != 0));
|
||||
var deskState = 0;
|
||||
if (desktop != null) { deskState = desktop.State; }
|
||||
|
||||
// Show the right buttons
|
||||
QV('disconnectbutton1span', (deskState == true));
|
||||
QV('connectbutton1span', (deskState == false) && (mesh.mtype == 2));
|
||||
QV('connectbutton1hspan', (deskState == false) && (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
|
||||
QV('disconnectbutton1span', (deskState != 0));
|
||||
QV('connectbutton1span', (deskState == 0) && (mesh.mtype == 2));
|
||||
QV('connectbutton1hspan', (deskState == 0) && (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
|
||||
|
||||
// Show the right settings
|
||||
QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == false) || (desktop.contype == 2)));
|
||||
QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == 0) || (desktop.contype == 2)));
|
||||
QV('d7meshkvm', (mesh.mtype == 2) && ((deskState == false) || (desktop.contype == 1)));
|
||||
|
||||
// Enable buttons
|
||||
|
@ -3184,6 +3200,11 @@
|
|||
QE('connectbutton1', online);
|
||||
var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
|
||||
QE('connectbutton1h', hwonline);
|
||||
QE('deskSaveBtn', deskState == 3);
|
||||
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus));
|
||||
QE('DeskCAD', deskState == 3);
|
||||
QE('DeskToolsButton', online);
|
||||
if (online == false) QV('DeskTools', false);
|
||||
}
|
||||
|
||||
// Debug
|
||||
|
@ -3232,12 +3253,9 @@
|
|||
var xstate = state;
|
||||
if ((xstate == 3) && (xdesktop.contype == 2)) { xstate++; }
|
||||
var str = StatusStrs[xstate];
|
||||
if (desktop.webRtcActive == true) { str += ', WebRTC'; }
|
||||
if ((desktop != null) && (desktop.webRtcActive == true)) { str += ', WebRTC'; }
|
||||
//if (desktop.m.stopInput == true) { str += ', Loopback'; }
|
||||
QH('deskstatus', str);
|
||||
QE('deskSaveBtn', state == 3);
|
||||
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (state != 0) && (desktopsettings.showfocus));
|
||||
QE('DeskCAD', state == 3);
|
||||
switch (state) {
|
||||
case 0:
|
||||
// Disconnect and clean up the remote desktop
|
||||
|
@ -3364,6 +3382,44 @@
|
|||
desktop.m.sendcad();
|
||||
}
|
||||
|
||||
// Show process dialogs
|
||||
function toggleDeskTools() {
|
||||
if (xxdialogMode) return;
|
||||
if (QS('DeskTools').display == 'none') {
|
||||
QV('DeskTools', true);
|
||||
Q('DeskTools').nodeid = currentNode._id;
|
||||
refreshDeskTools();
|
||||
} else {
|
||||
QV('DeskTools', false);
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh all of the desktop tool panels
|
||||
function refreshDeskTools() {
|
||||
QV('DeskToolsRefreshButton', false);
|
||||
setTimeout(refreshDeskToolsEx, 500);
|
||||
meshserver.send({ action: 'msg', type:'ps', nodeid: currentNode._id });
|
||||
}
|
||||
function refreshDeskToolsEx() { QV('DeskToolsRefreshButton', true); }
|
||||
var deskTools = { sort: 1, msg: null };
|
||||
function sortProcess(sort) { deskTools.sort = sort; showDeskToolsProcesses(deskTools.msg); }
|
||||
function sortProcessPid(a, b) { if (a.p > b.p) return 1; if (a.p < b.p) return (-1); return 0; }
|
||||
function sortProcessName(a, b) { if (a.d > b.d) return 1; if (a.d < b.d) return (-1); return 0; }
|
||||
function showDeskToolsProcesses(message) {
|
||||
deskTools.msg = message;
|
||||
if (message == null) { QH('DeskToolsProcesses', ''); return; }
|
||||
if (Q('DeskTools').nodeid != message.nodeid) return;
|
||||
var p = [], processes = null;
|
||||
try { processes = JSON.parse(message.value); } catch (e) { }
|
||||
if (processes != null) {
|
||||
for (var pid in processes) { p.push( { p:parseInt(pid), c:processes[pid].cmd, d:processes[pid].cmd.toLowerCase(), u: processes[pid].user } ); }
|
||||
if (deskTools.sort == 0) { p.sort(sortProcessPid); } else if (deskTools.sort == 1) { p.sort(sortProcessName); }
|
||||
var x = '';
|
||||
for (var i in p) { if (p[i].p != 0) { x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + p[i].p + '</div><a style=float:right;padding-right:5px;cursor:pointer title="Stop process" onclick=stopProcess(' + p[i].p + ',"' + p[i].c + '")><img width=10 height=10 src="images/trash.png"></a><div style=float:right;padding-right:5px>' + (p[i].u?p[i].u:'') + '</div><div>' + p[i].c + '</div></div>'; } }
|
||||
QH('DeskToolsProcesses', x);
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle mouse and keyboard input
|
||||
function toggleKvmControl() { putstore('DeskControl', (Q("DeskControl").checked?1:0)); }
|
||||
|
||||
|
@ -3393,6 +3449,8 @@
|
|||
function dmousemove(e) { if (!xxdialogMode && desktop != null && Q('DeskControl').checked) desktop.m.mousemove(e) }
|
||||
function dmousewheel(e) { if (!xxdialogMode && desktop != null && Q('DeskControl').checked) { desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
|
||||
function drotate(x) { if (!xxdialogMode && desktop != null) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); deskAdjust(); } }
|
||||
function stopProcess(id, name) { setDialogMode(2, "Process Control", 3, stopProcessEx, 'Stop process #' + id + ' "' + name + '"?', id); }
|
||||
function stopProcessEx(buttons, tag) { meshserver.send({ action: 'msg', type:'pskill', nodeid: currentNode._id, value: tag }); setTimeout(refreshDeskTools, 300); }
|
||||
|
||||
//
|
||||
// TERMINAL
|
||||
|
|
Loading…
Reference in a new issue