Improved multi-desktop support

This commit is contained in:
Ylian Saint-Hilaire 2018-03-30 15:26:36 -07:00
parent ca94c192ac
commit 2526a0841c
12 changed files with 249 additions and 58 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.

View File

@ -226,7 +226,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
var meshIdStart = '/' + username; var meshIdStart = '/' + username;
obj.db.GetAllType('mesh', function (err, docs) { obj.db.GetAllType('mesh', function (err, docs) {
var mesh = null; var mesh = null;
for (var i in docs) { if (docs[i]._id.indexOf(meshIdStart) > 0) { mesh = docs[i]; break; } } for (var i in docs) { if (docs[i]._id.replace(/\@/g, 'X').replace(/\$/g, 'X').indexOf(meshIdStart) > 0) { mesh = docs[i]; break; } }
if (mesh == null) { Debug(1, 'MPS:Mesh not found', username, password); SendUserAuthFail(socket); return -1; } if (mesh == null) { Debug(1, 'MPS:Mesh not found', username, password); SendUserAuthFail(socket); return -1; }
// If this is a agent-less mesh, use the device guid 3 times as ID. // If this is a agent-less mesh, use the device guid 3 times as ID.

View File

@ -1,6 +1,6 @@
{ {
"name": "meshcentral", "name": "meshcentral",
"version": "0.1.5-k", "version": "0.1.5-r",
"keywords": [ "keywords": [
"Remote Management", "Remote Management",
"Intel AMT", "Intel AMT",

View File

@ -159,7 +159,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
} }
obj.ProcessScreenMsg = function (width, height) { obj.ProcessScreenMsg = function (width, height) {
obj.Debug("ScreenSize: " + width + " x " + height); //obj.Debug("ScreenSize: " + width + " x " + height);
obj.Canvas.setTransform(1, 0, 0, 1, 0, 0); obj.Canvas.setTransform(1, 0, 0, 1, 0, 0);
obj.rotation = 0; obj.rotation = 0;
obj.FirstDraw = true; obj.FirstDraw = true;

View File

@ -70,7 +70,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
} }
} }
function sendCtrlMsg(x) { if (obj.ctrlMsgAllowed == true) { try { obj.socket.send(x); } catch (e) { } } } function sendCtrlMsg(x) { if (obj.ctrlMsgAllowed == true) { try { obj.socket.send(x); } catch (ex) { } } }
function performWebRtcSwitch() { function performWebRtcSwitch() {
if ((obj.webSwitchOk == true) && (obj.webRtcActive == true)) { if ((obj.webSwitchOk == true) && (obj.webRtcActive == true)) {
@ -94,7 +94,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
//console.log('Recv', e.data, obj.State); //console.log('Recv', e.data, obj.State);
if (obj.State < 3) { if (obj.State < 3) {
if (e.data == 'c') { if (e.data == 'c') {
obj.socket.send(obj.protocol); try { obj.socket.send(obj.protocol); } catch (ex) { }
obj.xxStateChange(3); obj.xxStateChange(3);
if (obj.attemptWebRTC == true) { if (obj.attemptWebRTC == true) {
@ -109,7 +109,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
obj.webchannel.onclose = function (event) { /*console.log('WebRTC close');*/ if (obj.webRtcActive) { obj.Stop(); } } obj.webchannel.onclose = function (event) { /*console.log('WebRTC close');*/ if (obj.webRtcActive) { obj.Stop(); } }
obj.webrtc.onicecandidate = function (e) { obj.webrtc.onicecandidate = function (e) {
if (e.candidate == null) { if (e.candidate == null) {
obj.socket.send(JSON.stringify(obj.webrtcoffer)); // End of candidates, send the offer try { obj.socket.send(JSON.stringify(obj.webrtcoffer)); } catch (ex) { } // End of candidates, send the offer
} else { } else {
obj.webrtcoffer.sdp += ("a=" + e.candidate.candidate + "\r\n"); // New candidate, add it to the SDP obj.webrtcoffer.sdp += ("a=" + e.candidate.candidate + "\r\n"); // New candidate, add it to the SDP
} }
@ -177,23 +177,25 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
obj.send = function (x) { obj.send = function (x) {
//obj.debug("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + rstr2hex(x)); //obj.debug("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + rstr2hex(x));
//console.log("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + ((typeof x == 'string')?x:rstr2hex(x))); //console.log("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + ((typeof x == 'string')?x:rstr2hex(x)));
if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) { try {
if (typeof x == 'string') { if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) {
if (obj.debugmode == 1) { if (typeof x == 'string') {
var b = new Uint8Array(x.length), c = []; if (obj.debugmode == 1) {
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); c.push(x.charCodeAt(i)); } var b = new Uint8Array(x.length), c = [];
if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); } for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); c.push(x.charCodeAt(i)); }
//console.log('Send', c); if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
//console.log('Send', c);
} else {
var b = new Uint8Array(x.length);
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
}
} else { } else {
var b = new Uint8Array(x.length); //if (obj.debugmode == 1) { console.log('Send', x); }
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); } if (obj.webRtcActive == true) { obj.webchannel.send(x); } else { obj.socket.send(x); }
if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
} }
} else {
//if (obj.debugmode == 1) { console.log('Send', x); }
if (obj.webRtcActive == true) { obj.webchannel.send(x); } else { obj.socket.send(x); }
} }
} } catch (ex) { }
} }
obj.xxOnSocketClosed = function () { obj.xxOnSocketClosed = function () {

View File

@ -8,6 +8,7 @@
var CreateAmtRemoteDesktop = function (divid, scrolldiv) { var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
var obj = {}; var obj = {};
obj.canvasid = divid; obj.canvasid = divid;
obj.CanvasId = Q(divid);
obj.scrolldiv = scrolldiv; obj.scrolldiv = scrolldiv;
obj.canvas = Q(divid).getContext("2d"); obj.canvas = Q(divid).getContext("2d");
obj.protocol = 2; // KVM obj.protocol = 2; // KVM

View File

@ -115,6 +115,12 @@
<input id=SearchInput type=text style=width:120px placeholder=Search onchange=onSearchInputChanged() onkeyup=onSearchInputChanged() autocomplete=off onfocus=onSearchFocus(1) onblur=onSearchFocus(0) />&nbsp; <input id=SearchInput type=text style=width:120px placeholder=Search onchange=onSearchInputChanged() onkeyup=onSearchInputChanged() autocomplete=off onfocus=onSearchFocus(1) onblur=onSearchFocus(0) />&nbsp;
<input type=checkbox id=HostnameCheckBox onclick=onHostnameCheckBox() /><span title="Show device hostnames">Hostname</span> <input type=checkbox id=HostnameCheckBox onclick=onHostnameCheckBox() /><span title="Show device hostnames">Hostname</span>
</div> </div>
<div id=kvmListToolbar class=style14 style=height:100%;float:left>
&nbsp;&nbsp;<input type="button" onclick="connectAllKvmFunction();" value="Connect All" />&nbsp;
<input type="button" onclick="disconnectAllKvmFunction();" value="Disconnect All" />&nbsp;
<input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" />AutoConnect&nbsp;
<input type="button" onclick="showMultiDesktopSettings();" value="Settings" />&nbsp;
</div>
<div id=devMapToolbar class=style14 style=height:100%;float:left> <div id=devMapToolbar class=style14 style=height:100%;float:left>
&nbsp;&nbsp;<input type=text id=mapSearchLocation placeholder="Search Location" onfocus=onMapSearchFocus(1) onblur=onMapSearchFocus(0) /> &nbsp;&nbsp;<input type=text id=mapSearchLocation placeholder="Search Location" onfocus=onMapSearchFocus(1) onblur=onMapSearchFocus(0) />
<input type=button value=Search title="Search for location" onclick=getSearchLocation() /> <input type=button value=Search title="Search for location" onclick=getSearchLocation() />
@ -128,7 +134,8 @@
<select id=viewselect onchange=onDeviceViewChange()> <select id=viewselect onchange=onDeviceViewChange()>
<option value=1>Columns</option> <option value=1>Columns</option>
<option value=2>List</option> <option value=2>List</option>
<option id=viewselectmapoption value=3>Map</option> <option value=3>Desktops</option>
<option id=viewselectmapoption value=4>Map</option>
</select> </select>
</div> </div>
<div style=float:right id=devListToolbarSort> <div style=float:right id=devListToolbarSort>
@ -140,6 +147,15 @@
</select> </select>
&nbsp; &nbsp;
</div> </div>
<div style=float:right id=devListToolbarSize>
Size
<select id=sizeselect onchange=onDeviceViewChange()>
<option value=0>Small</option>
<option value=1>Medium</option>
<option value=2>Large</option>
</select>
&nbsp;
</div>
</div> </div>
</div> </div>
<div id=NoMeshesPanel style=display:none> <div id=NoMeshesPanel style=display:none>
@ -338,7 +354,9 @@
<tr id=deskarea3> <tr id=deskarea3>
<td id=deskarea3x style="background:black;text-align:center;height:400px;position:relative"> <td id=deskarea3x style="background:black;text-align:center;height:400px;position:relative">
<div id="DeskFocus" style="color:transparent;border:3px dotted rgba(255,0,0,.2);position:absolute;border-radius:5px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></div> <div id="DeskFocus" style="color:transparent;border:3px dotted rgba(255,0,0,.2);position:absolute;border-radius:5px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></div>
<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 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>
</td> </td>
</tr> </tr>
<tr id=deskarea4> <tr id=deskarea4>
@ -635,10 +653,12 @@
var nodeShortIdent = 0; var nodeShortIdent = 0;
var desktop; var desktop;
var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024 }; var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024 };
var multidesktopsettings = { quality: 30, scaling: 128 };
var terminal; var terminal;
var files; var files;
var debugLevel = {{{debuglevel}}}; var debugLevel = {{{debuglevel}}};
var features = {{{features}}}; var features = {{{features}}};
var multiDesktop = {};
var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}"; var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}";
var amtScanResults = null; var amtScanResults = null;
var debugmode = false; var debugmode = false;
@ -695,7 +715,8 @@
meshserver.Start(); meshserver.Start();
// Setup page controls // Setup page controls
document.getElementById("sortselect").selectedIndex = sort = getstore("sort", 0); Q('sortselect').selectedIndex = sort = getstore("sort", 0);
Q('sizeselect').selectedIndex = getstore("viewsize", 1);
Q('SearchInput').value = getstore("search", ""); Q('SearchInput').value = getstore("search", "");
showHostnames = (getstore("showHostnames", 0) == 1); showHostnames = (getstore("showHostnames", 0) == 1);
Q('HostnameCheckBox').checked = showHostnames; Q('HostnameCheckBox').checked = showHostnames;
@ -723,8 +744,10 @@
setInterval(updateDeviceTimeline, 120000); // Check every 2 minutes setInterval(updateDeviceTimeline, 120000); // Check every 2 minutes
// Load desktop settings // Load desktop settings
t = localStorage.getItem('desktopsettings'); var t = localStorage.getItem('desktopsettings');
if (t != null) { desktopsettings = JSON.parse(t); } if (t != null) { desktopsettings = JSON.parse(t); }
t = localStorage.getItem('multidesktopsettings');
if (t != null) { multidesktopsettings = JSON.parse(t); }
applyDesktopSettings(); applyDesktopSettings();
// Mouse Scroll on desktop // Mouse Scroll on desktop
@ -1260,6 +1283,7 @@
function onDeviceViewChange() { function onDeviceViewChange() {
putstore("deviceView", Q('viewselect').value); putstore("deviceView", Q('viewselect').value);
putstore("viewsize", Q('sizeselect').value);
updateDevices(); updateDevices();
} }
@ -1331,26 +1355,29 @@
var deviceHeaderCount; var deviceHeaderCount;
var deviceHeaders = {}; var deviceHeaders = {};
function updateDevices() { function updateDevices() {
var r = "", c = 0, current = null, count = 0, displayedMeshes = {}, view = Q('viewselect').value; var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, view = Q('viewselect').value;
QV('xdevices', view < 3); QV('xdevices', view < 4);
QV('xdevicesmap', view == 3); QV('xdevicesmap', view == 4);
QV('devListToolbar', view < 3); QV('devListToolbar', view < 3);
QV('devMapToolbar', view == 3); QV('kvmListToolbar', view == 3);
QV('devListToolbarSort', view < 3); QV('devMapToolbar', view == 4);
QV('devListToolbarSort', view < 4);
QV('devListToolbarSize', view == 3);
QV('NoMeshesPanel', meshcount == 0); QV('NoMeshesPanel', meshcount == 0);
QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0)); QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0));
QV('devListToolbarSort', (meshcount != 0) && (nodes.length > 0)); QV('devListToolbarSort', (meshcount != 0) && (nodes.length > 0));
if ((meshcount == 0) || (nodes.length == 0)) { view = 1; } if ((meshcount == 0) || (nodes.length == 0)) { view = 1; }
if (view == 3) { if (view == 4) {
setTimeout( function() { if (xxmap.map != null) { xxmap.map.updateSize(); } }, 200); setTimeout( function() { if (xxmap.map != null) { xxmap.map.updateSize(); } }, 200);
// TODO // TODO
} else { } else {
// 3 wide or list view // 3 wide, list view or desktop view
deviceHeaderId = 0; deviceHeaderId = 0;
deviceHeaderCount = {}; deviceHeaderCount = {};
deviceHeaderTotal = 0; deviceHeaderTotal = 0;
deviceHeaders = {}; deviceHeaders = {};
deviceHeadersTitles = {}; deviceHeadersTitles = {};
var kvmDivs = [];
// Save the list of currently checked nodeid's // Save the list of currently checked nodeid's
var checkedNodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0; var checkedNodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
@ -1361,14 +1388,15 @@
if (nodes[i].v == false) continue; if (nodes[i].v == false) continue;
var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()]; var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
if (meshlinks == null) continue; if (meshlinks == null) continue;
var meshrights = meshlinks.rights;
if ((view == 3) && (mesh2.mtype == 1)) continue;
if (sort == 0) { if (sort == 0) {
// Mesh header // Mesh header
if (nodes[i].meshid != current) { if (nodes[i].meshid != current) {
deviceHeaderSet(); deviceHeaderSet();
var extra = ''; var extra = '';
if (meshes[nodes[i].meshid].mtype == 1) { extra = '<span class=devHeaderx>, Intel&reg; AMT only</span>'; } if (meshes[nodes[i].meshid].mtype == 1) { extra = '<span class=devHeaderx>, Intel&reg; AMT only</span>'; }
var meshrights = meshlinks.rights; if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } r += '</tr></table>'; }
r += '<div class=DevSt style=width:100%;padding-top:4px><span style=float:right>'; r += '<div class=DevSt style=width:100%;padding-top:4px><span style=float:right>';
r += getMeshActions(mesh2, meshrights); r += getMeshActions(mesh2, meshrights);
r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + nodes[i].meshid + '")>' + EscapeHtml(meshes[nodes[i].meshid].name) + '</span>' + extra + '<span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx></span></div>'; r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + nodes[i].meshid + '")>' + EscapeHtml(meshes[nodes[i].meshid].name) + '</span>' + extra + '<span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx></span></div>';
@ -1380,7 +1408,7 @@
// Power header // Power header
if (nodes[i].pwr !== current) { if (nodes[i].pwr !== current) {
deviceHeaderSet(); deviceHeaderSet();
if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } r += '</tr></table>'; } if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
r += '<div class=DevSt style=width:100%;padding-top:4px><span>' + PowerStateStr2(nodes[i].pwr) + '</span><span id=DevxHeader' + deviceHeaderId + ' class="devHeaderx"></span></div>'; r += '<div class=DevSt style=width:100%;padding-top:4px><span>' + PowerStateStr2(nodes[i].pwr) + '</span><span id=DevxHeader' + deviceHeaderId + ' class="devHeaderx"></span></div>';
current = nodes[i].pwr; current = nodes[i].pwr;
c = 0; c = 0;
@ -1404,12 +1432,19 @@
if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; } if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; }
if (view == 1) { if (view == 1) {
r += '<div id=devs style=display:inline-block;width:301px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div><div style=height:100%;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class="i' + icon + '" style=width:50px;float:left></div><div style=height:100%><div class=g1></div><div class=e2><div class=e1 title="' + title + '">' + name + '</div><div>' + nodestate + '</div></div><div class=g2></div></div></div></div>'; r += '<div id=devs style=display:inline-block;width:301px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div><div style=height:100%;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class="i' + icon + '" style=width:50px;float:left></div><div style=height:100%><div class=g1></div><div class=e2><div class=e1 title="' + title + '">' + name + '</div><div>' + nodestate + '</div></div><div class=g2></div></div></div></div>';
} else { } else if (view == 2) {
r += '<tr><td><div id=devs class=bar18 style=height:18px;width:100%;font-size:medium>'; r += '<tr><td><div id=devs class=bar18 style=height:18px;width:100%;font-size:medium>';
r += '<div style=width:22px;float:left;background-color:white><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div>'; r += '<div style=width:22px;float:left;background-color:white><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div>';
r += '<div style=float:left;height:18px;width:18px;background-color:white onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class=j' + icon + ' style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>'; r += '<div style=float:left;height:18px;width:18px;background-color:white onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class=j' + icon + ' style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>'; r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
r += '<div style=cursor:pointer;font-size:14px title="' + title + '" onclick=gotoDevice(\'' + nodes[i]._id + '\')><span style=float:right>' + nodestate + '</span><span style=width:300px>' + name + '</span></div></div></td></tr>'; r += '<div style=cursor:pointer;font-size:14px title="' + title + '" onclick=gotoDevice(\'' + nodes[i]._id + '\')><span style=float:right>' + nodestate + '</span><span style=width:300px>' + name + '</span></div></div></td></tr>';
} else if ((view == 3) && (nodes[i].conn & 1) && ((meshrights & 8) != 0)) {
r += '<div id=devs style=display:inline-block;margin:1px;background-color:lightgray;border-radius:5px;position:relative><div style=padding:3px;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\',11)>';
//r += '<input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox style=float:left>';
r += '<div class="j' + icon + '" style=width:16px;float:left></div>&nbsp;' + name + '</div>';
r += '<span onclick=gotoDevice(\'' + nodes[i]._id + '\')></span><div id=xkvmid_' + nodes[i]._id.split('/')[2] + '><div id=skvmid_' + nodes[i]._id.split('/')[2] + ' style="position:absolute;color:white;left:5px;top:27px;text-shadow:0px 0px 5px #000;z-index:1000;cursor:default" onclick=toggleKvmDevice(\'' + nodes[i]._id + '\')>Disconnected</div></div>';
r += '</div>';
kvmDivs.push(nodes[i]._id);
} }
deviceHeaderTotal++; deviceHeaderTotal++;
@ -1419,13 +1454,13 @@
if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding
// Display all empty meshes, we need to do this because users can add devices to these at any time. // Display all empty meshes, we need to do this because users can add devices to these at any time.
if (sort == 0 && Q('SearchInput').value == '') { if ((sort == 0) && (Q('SearchInput').value == '') && (view < 3)) {
for (var i in meshes) { for (var i in meshes) {
var mesh = meshes[i], meshlink = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()]; var mesh = meshes[i], meshlink = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
if (meshlink != null) { if (meshlink != null) {
var meshrights = meshlink.rights; var meshrights = meshlink.rights;
if (displayedMeshes[mesh._id] == null) { if (displayedMeshes[mesh._id] == null) {
if (current != '') { r += '</tr></table>'; } if ((current != '') && (r != '')) { r += '</tr></table>'; }
r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span style=float:right>'; r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span style=float:right>';
r += getMeshActions(mesh, meshrights); r += getMeshActions(mesh, meshrights);
r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></td></tr><tr>'; r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></td></tr><tr>';
@ -1462,6 +1497,132 @@
for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); } for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; } for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
p1updateInfo(); p1updateInfo();
// Take care of KVM surfaces in desktop view mode
if (view == 3) {
var vsize = [{x:180,y:101}, {x:302,y:169}, {x:454,y:255}][Q('sizeselect').selectedIndex];
for (var i in multiDesktop) { multiDesktop[i].xxdelete = true; }
for (var i in kvmDivs) {
var id = kvmDivs[i], shortid = id.split('/')[2], desk = multiDesktop[id];
if (desk != null) {
// This device already has a canvas, use it.
desk.m.CanvasId.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
Q('xkvmid_' + shortid).appendChild(desk.m.CanvasId);
delete desk.xxdelete;
QH('skvmid_' + shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][((desk.m.State == null)?desk.m.state:desk.m.State)]);
} else {
var node = getNodeFromId(id);
if ((desktopNode == node) && (desktop != null)) { // Check if the main desktop is this device, if it is, use that.
// This device already has a canvas, use it.
var c = desktop.m.CanvasId;
c.setAttribute('id', 'kvmid_' + shortid);
c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
c.removeAttribute('onmousedown');
c.removeAttribute('onmouseup');
c.removeAttribute('onmousemove');
Q('xkvmid_' + shortid).appendChild(c);
QH('skvmid_' + shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][((desktop.m.State == null)?desktop.m.state:desktop.m.State)]);
if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling); }
desktop.shortid = shortid;
desktop.onStateChanged = onMultiDesktopStateChange;
multiDesktop[id] = desktop;
desktop = desktopNode = currentNode = null;
// Setup a replacement desktop
QH('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>');
} else {
// This is a new device, create a canvas for it.
var c = document.createElement('canvas');
c.setAttribute('id', 'kvmid_' + shortid);
c.setAttribute('width', 640);
c.setAttribute('height', 200);
c.setAttribute('oncontextmenu', 'return false');
c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
Q('xkvmid_' + shortid).appendChild(c);
// Check if we need to auto-connect
if (Q('autoConnectDesktopCheckbox').checked == true) { setTimeout(function() { connectMultiDesktop(node, 1); }, 100); }
}
}
}
for (var i in multiDesktop) {
// If a device is no longer viewed, disconnect it.
if (multiDesktop[i].xxdelete == true) { multiDesktop[i].Stop(); delete multiDesktop[i]; }
}
} else {
disconnectAllKvmFunction();
Q('autoConnectDesktopCheckbox').checked = false;
}
}
}
function toggleKvmDevice(nodeid) {
var node = getNodeFromId(nodeid), mesh = meshes[node.meshid], meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
if ((meshrights & 8) != 0) { // Requires remote control rights
//var conn = 0;
//if ((node.conn & 1) != 0) { conn = 1; } else if ((node.conn & 6) != 0) { conn = 2; } // Check what type of connect we can do (Agent vs AMT)
if (node.conn & 1) { connectMultiDesktop(node, 1); }
}
}
function autoConnectDesktops() { if (Q('autoConnectDesktopCheckbox').checked == true) { connectAllKvmFunction(); } }
function connectAllKvmFunction() { for (var i in nodes) { if (multiDesktop[nodes[i]._id] == null) { toggleKvmDevice(nodes[i]._id); } } }
function disconnectAllKvmFunction() { for (var nodeid in multiDesktop) { multiDesktop[nodeid].Stop(); } multiDesktop = {}; }
function onMultiDesktopStateChange(desk, state) { try { QH('skvmid_' + desk.shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][state]); } catch (ex) {} }
function showMultiDesktopSettings() {
QV('d7amtkvm', false);
QV('d7meshkvm', true);
d7bitmapquality.value = multidesktopsettings.quality;
d7bitmapscaling.value = multidesktopsettings.scaling;
setDialogMode(7, "Remote Desktop Settings", 3, showMultiDesktopSettingsChanged);
}
function showMultiDesktopSettingsChanged() {
multidesktopsettings.quality = d7bitmapquality.value;
multidesktopsettings.scaling = d7bitmapscaling.value;
localStorage.setItem('multidesktopsettings', JSON.stringify(multidesktopsettings));
// Make changes to all current connections
for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(1,multidesktopsettings.quality,multidesktopsettings.scaling); }
}
function connectMultiDesktop(node, contype) {
var nodeid = node._id;
var desk = multiDesktop[nodeid];
if (desk == null) {
if (contype == 2) {
// Setup the Intel AMT remote desktop
if ((node.intelamt.user == null) || (node.intelamt.user == '')) { return; }
desk = CreateAmtRedirect(CreateAmtRemoteDesktop('kvmid_' + nodeid.split('/')[2]));
desk.shortid = nodeid.split('/')[2];
//desk.debugmode = debugmode;
desk.onStateChanged = onMultiDesktopStateChange;
desk.m.bpp = 1;
desk.m.useZRLE = true;
desk.m.showmouse = true;
//desk.m.onScreenSizeChange = deskAdjust;
desk.Start(nodeid, 16994, '*', '*', 0);
desk.contype = 2;
multiDesktop[nodeid] = desk;
} else if (contype == 1) {
// Setup the Mesh Agent remote desktop
desk = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('kvmid_' + nodeid.split('/')[2]), serverPublicNamePort);
desk.shortid = nodeid.split('/')[2];
desk.attemptWebRTC = attemptWebRTC;
desk.onStateChanged = onMultiDesktopStateChange;
desk.m.CompressionLevel = multidesktopsettings.quality;
desk.m.ScalingLevel = multidesktopsettings.scaling;
//desk.m.onDisplayinfo = deskDisplayInfo;
//desk.m.onScreenSizeChange = deskAdjust;
desk.Start(nodeid);
desk.contype = 1;
multiDesktop[nodeid] = desk;
}
} else {
// Disconnect and clean up the remote desktop
desk.Stop();
delete multiDesktop[nodeid];
} }
} }
@ -1546,8 +1707,9 @@
function addCiraDeviceToMesh(meshid) { function addCiraDeviceToMesh(meshid) {
if (xxdialogMode) return; if (xxdialogMode) return;
var mesh = meshes[meshid]; var mesh = meshes[meshid];
var meshidx = meshid.substring(5);
if (meshidx[0] == '/') meshidx = meshidx.substring(1); // Replace non alphabetic characters (@ and $) with 'X' because MPS username cannot accept it.
var meshidx = meshid.split('/')[2].replace(/\@/g, 'X').replace(/\$/g, 'X');
var y = '<select id=dlgAddCiraSel onclick=dlgAddCiraSelClick() style=width:230px><option value=0>MeshCommander Script</option><option value=1>Manual Username/Password</option>'; var y = '<select id=dlgAddCiraSel onclick=dlgAddCiraSelClick() style=width:230px><option value=0>MeshCommander Script</option><option value=1>Manual Username/Password</option>';
if ((features & 16) == 0) { y += '<option value=2>Manual Certificate</option></select>'; } // Only display this option if Intel AMT CIRA with Mutual-Auth is allowed. if ((features & 16) == 0) { y += '<option value=2>Manual Certificate</option></select>'; } // Only display this option if Intel AMT CIRA with Mutual-Auth is allowed.
@ -1601,8 +1763,6 @@
function inviteAgentToMesh(meshid) { function inviteAgentToMesh(meshid) {
if (xxdialogMode) return; if (xxdialogMode) return;
var mesh = meshes[meshid]; var mesh = meshes[meshid];
var meshidx = meshid.substring(5);
if (meshidx[0] == '/') meshidx = meshidx.substring(1);
var x = "Invite someone to install the mesh agent. An email with be sent with the link to the mesh agent installation for " + EscapeHtml(mesh.name) + ".<br /><br />"; var x = "Invite someone to install the mesh agent. An email with be sent with the link to the mesh agent installation for " + EscapeHtml(mesh.name) + ".<br /><br />";
x += addHtmlValue('E-Mail', '<input id=agentInviteEmail style=width:240px onkeyup=validateAgentInvite()></input>'); x += addHtmlValue('E-Mail', '<input id=agentInviteEmail style=width:240px onkeyup=validateAgentInvite()></input>');
setDialogMode(2, "Invite Mesh Agent", 3, performAgentInvite, x, meshid); setDialogMode(2, "Invite Mesh Agent", 3, performAgentInvite, x, meshid);
@ -1619,10 +1779,7 @@
function addAgentToMesh(meshid) { function addAgentToMesh(meshid) {
if (xxdialogMode) return; if (xxdialogMode) return;
var mesh = meshes[meshid]; var mesh = meshes[meshid], x = '';
var meshidx = meshid.substring(5);
if (meshidx[0] == '/') meshidx = meshidx.substring(1);
var x = "";
x += addHtmlValue('Operating System', '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>Windows</option><option value=1>Linux</option><option value=2>Windows (UnInstall)</option><option value=3>Linux (UnInstall)</option></select>') + '<hr>'; x += addHtmlValue('Operating System', '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>Windows</option><option value=1>Linux</option><option value=2>Windows (UnInstall)</option><option value=3>Linux (UnInstall)</option></select>') + '<hr>';
// Windows agent install // Windows agent install
@ -2459,8 +2616,7 @@
} }
function getNodeRights(nodeid) { function getNodeRights(nodeid) {
var node = getNodeFromId(nodeid); var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
var mesh = meshes[node.meshid];
return mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights; return mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
} }
@ -2471,6 +2627,7 @@
var powerTimeline = null; var powerTimeline = null;
function getCurrentNode() { return currentNode; }; function getCurrentNode() { return currentNode; };
function gotoDevice(nodeid, panel, refresh) { function gotoDevice(nodeid, panel, refresh) {
//disconnectAllKvmFunction();
var node = getNodeFromId(nodeid); var node = getNodeFromId(nodeid);
var mesh = meshes[node.meshid]; var mesh = meshes[node.meshid];
var meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights; var meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
@ -2607,7 +2764,6 @@
Q('MainComputerImage').className = ((!node.conn) || (node.conn == 0)?'gray':''); Q('MainComputerImage').className = ((!node.conn) || (node.conn == 0)?'gray':'');
// Setup/Refresh the desktop tab // Setup/Refresh the desktop tab
setupDesktop();
setupTerminal(); setupTerminal();
setupFiles(); setupFiles();
var consoleRights = ((meshrights & 16) != 0); var consoleRights = ((meshrights & 16) != 0);
@ -2640,6 +2796,7 @@
// Request the power timeline // Request the power timeline
if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { powerTimelineReq = currentNode._id; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); } if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { powerTimelineReq = currentNode._id; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
} }
setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
if (!panel) panel = 10; if (!panel) panel = 10;
go(panel); go(panel);
} }
@ -2917,7 +3074,7 @@
var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc']; var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc'];
function showEditNodeValueDialog(mode) { function showEditNodeValueDialog(mode) {
if (xxdialogMode) return; if (xxdialogMode) return;
var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:230px maxlength=32 onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />'); var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:230px maxlength=64 onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode); setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode);
var v = currentNode[showEditNodeValueDialog_modes2[mode]]; var v = currentNode[showEditNodeValueDialog_modes2[mode]];
if (v == null) v = ''; if (v == null) v = '';
@ -2945,7 +3102,34 @@
var desktopNode; var desktopNode;
function setupDesktop() { function setupDesktop() {
// Setup the remote desktop // Setup the remote desktop
if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); delete desktop; desktop = null; } if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); delete desktop; desktopNode = null; desktop = null; }
// If the device desktop is already connected in multi-desktop, use that.
if ((desktopNode != currentNode) || (desktop == null)) {
var xdesk = multiDesktop[currentNode._id];
if (xdesk != null) {
// This device already has a canvas, use it.
QH('DeskParent', '');
var c = xdesk.m.CanvasId;
c.setAttribute('id', 'Desk');
c.setAttribute('style', 'width:100%;-ms-touch-action:none;margin-left:0px');
c.setAttribute('onmousedown', 'dmousedown(event)');
c.setAttribute('onmouseup', 'dmouseup(event)');
c.setAttribute('onmousemove', 'dmousemove(event)');
c.removeAttribute('onclick');
Q('DeskParent').appendChild(c);
desktop = xdesk;
if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling); }
desktop.onStateChanged = onDesktopStateChange;
desktopNode = currentNode;
onDesktopStateChange(desktop, desktop.State);
delete multiDesktop[currentNode._id];
} else {
// Device is not already connected, just setup a blank canvas
QH('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>');
desktopNode = currentNode;
}
}
desktopNode = currentNode; desktopNode = currentNode;
updateDesktopButtons(); updateDesktopButtons();
@ -2955,22 +3139,22 @@
// Show and enable the right buttons // Show and enable the right buttons
function updateDesktopButtons() { function updateDesktopButtons() {
var mesh = meshes[desktopNode.meshid]; var mesh = meshes[currentNode.meshid];
var deskState = ((desktop != null) && (desktop.state != 0)); var deskState = ((desktop != null) && (desktop.state != 0));
// Show the right buttons // Show the right buttons
QV('disconnectbutton1span', (deskState == true)); QV('disconnectbutton1span', (deskState == true));
QV('connectbutton1span', (deskState == false) && (mesh.mtype == 2)); QV('connectbutton1span', (deskState == false) && (mesh.mtype == 2));
QV('connectbutton1hspan', (deskState == false) && (desktopNode.intelamt != null && ((desktopNode.intelamt.ver != null) || (mesh.mtype == 1)))); QV('connectbutton1hspan', (deskState == false) && (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
// Show the right settings // Show the right settings
QV('d7amtkvm', (desktopNode.intelamt != null && ((desktopNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == false) || (desktop.contype == 2))); QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == false) || (desktop.contype == 2)));
QV('d7meshkvm', (mesh.mtype == 2) && ((deskState == false) || (desktop.contype == 1))); QV('d7meshkvm', (mesh.mtype == 2) && ((deskState == false) || (desktop.contype == 1)));
// Enable buttons // Enable buttons
var online = ((desktopNode.conn & 1) != 0); // If Agent (1) connected, enable Terminal var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable Terminal
QE('connectbutton1', online); QE('connectbutton1', online);
var hwonline = ((desktopNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
QE('connectbutton1h', hwonline); QE('connectbutton1h', hwonline);
} }
@ -2980,6 +3164,7 @@
function connectDesktop(e, contype) { function connectDesktop(e, contype) {
if (desktop == null) { if (desktop == null) {
desktopNode = currentNode;
if (contype == 2) { if (contype == 2) {
// Setup the Intel AMT remote desktop // Setup the Intel AMT remote desktop
if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; } if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
@ -3010,7 +3195,7 @@
// Disconnect and clean up the remote desktop // Disconnect and clean up the remote desktop
desktop.Stop(); desktop.Stop();
delete desktop; delete desktop;
desktop = null; desktopNode = desktop = null;
} }
} }
@ -3029,7 +3214,7 @@
// Disconnect and clean up the remote desktop // Disconnect and clean up the remote desktop
desktop.Stop(); desktop.Stop();
delete desktop; delete desktop;
desktop = null; desktopNode = desktop = null;
QV('DeskFocus', false); QV('DeskFocus', false);
QV('termdisplays', false); QV('termdisplays', false);
deskFocusBtn.value = 'All Focus'; deskFocusBtn.value = 'All Focus';
@ -3044,6 +3229,8 @@
} }
function showDesktopSettings() { function showDesktopSettings() {
applyDesktopSettings();
updateDesktopButtons();
setDialogMode(7, "Remote Desktop Settings", 3, showDesktopSettingsChanged); setDialogMode(7, "Remote Desktop Settings", 3, showDesktopSettingsChanged);
} }
@ -3074,7 +3261,7 @@
d7showfocus.checked = desktopsettings.showfocus; d7showfocus.checked = desktopsettings.showfocus;
d7showcursor.checked = desktopsettings.showmouse; d7showcursor.checked = desktopsettings.showmouse;
d7bitmapquality.value = 40; // Default value d7bitmapquality.value = 40; // Default value
if (ops.indexOf(desktopsettings.quality) >= 0) { d7bitmapquality.value = desktopsettings.quality; } if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
d7bitmapscaling.value = desktopsettings.scaling; d7bitmapscaling.value = desktopsettings.scaling;
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus)); QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus));
} }
@ -4925,6 +5112,7 @@
QS('MainDevConsole').backgroundColor = ((x == 15) ? "#003366" : "#808080"); QS('MainDevConsole').backgroundColor = ((x == 15) ? "#003366" : "#808080");
QV('MeshSubMenuSpan', x >= 20 && x < 30); QV('MeshSubMenuSpan', x >= 20 && x < 30);
QS('MeshGeneral').backgroundColor = ((x == 20) ? "#003366" : "#808080"); QS('MeshGeneral').backgroundColor = ((x == 20) ? "#003366" : "#808080");
if (x == 1) updateDevices();
} }
// Generic methods // Generic methods