Improved multi-desktop support
Ylian Saint-Hilaire committed
Mar 30, 2018 at 15:26 UTC
2526a0841c1769d5e9dff48863d04e191ed71f83
12 files changed
+249
-58
agents/MeshCmd-signed.exe
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
agents/MeshCmd64-signed.exe
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
agents/MeshService-signed.exe
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64-signed.exe
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
mpsserver.js
+1
-1
@@ -226,7 +226,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
226
var meshIdStart = '/' + username;
227
obj.db.GetAllType('mesh', function (err, docs) {
228
var mesh = null;
229
- for (var i in docs) { if (docs[i]._id.indexOf(meshIdStart) > 0) { mesh = docs[i]; break; } }
229
+ for (var i in docs) { if (docs[i]._id.replace(/\@/g, 'X').replace(/\$/g, 'X').indexOf(meshIdStart) > 0) { mesh = docs[i]; break; } }
230
if (mesh == null) { Debug(1, 'MPS:Mesh not found', username, password); SendUserAuthFail(socket); return -1; }
231
232
// If this is a agent-less mesh, use the device guid 3 times as ID.
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.1.5-k",
3
+ "version": "0.1.5-r",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
public/scripts/agent-desktop-0.0.2.js
+1
-1
@@ -159,7 +159,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
159
}
160
161
obj.ProcessScreenMsg = function (width, height) {
162
- obj.Debug("ScreenSize: " + width + " x " + height);
162
+ //obj.Debug("ScreenSize: " + width + " x " + height);
163
obj.Canvas.setTransform(1, 0, 0, 1, 0, 0);
164
obj.rotation = 0;
165
obj.FirstDraw = true;
public/scripts/agent-redir-ws-0.1.0.js
+19
-17
@@ -70,7 +70,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
70
}
71
}
72
73
- function sendCtrlMsg(x) { if (obj.ctrlMsgAllowed == true) { try { obj.socket.send(x); } catch (e) { } } }
73
+ function sendCtrlMsg(x) { if (obj.ctrlMsgAllowed == true) { try { obj.socket.send(x); } catch (ex) { } } }
74
75
function performWebRtcSwitch() {
76
if ((obj.webSwitchOk == true) && (obj.webRtcActive == true)) {
@@ -94,7 +94,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
94
//console.log('Recv', e.data, obj.State);
95
if (obj.State < 3) {
96
if (e.data == 'c') {
97
- obj.socket.send(obj.protocol);
97
+ try { obj.socket.send(obj.protocol); } catch (ex) { }
98
obj.xxStateChange(3);
99
100
if (obj.attemptWebRTC == true) {
@@ -109,7 +109,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
109
obj.webchannel.onclose = function (event) { /*console.log('WebRTC close');*/ if (obj.webRtcActive) { obj.Stop(); } }
110
obj.webrtc.onicecandidate = function (e) {
111
if (e.candidate == null) {
112
- obj.socket.send(JSON.stringify(obj.webrtcoffer)); // End of candidates, send the offer
112
+ try { obj.socket.send(JSON.stringify(obj.webrtcoffer)); } catch (ex) { } // End of candidates, send the offer
113
} else {
114
obj.webrtcoffer.sdp += ("a=" + e.candidate.candidate + "\r\n"); // New candidate, add it to the SDP
115
}
@@ -177,23 +177,25 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
177
obj.send = function (x) {
178
//obj.debug("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + rstr2hex(x));
179
//console.log("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + ((typeof x == 'string')?x:rstr2hex(x)));
180
- if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) {
181
- if (typeof x == 'string') {
182
- if (obj.debugmode == 1) {
183
- var b = new Uint8Array(x.length), c = [];
184
- for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); c.push(x.charCodeAt(i)); }
185
- if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
186
- //console.log('Send', c);
180
+ try {
181
+ if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) {
182
+ if (typeof x == 'string') {
183
+ if (obj.debugmode == 1) {
184
+ var b = new Uint8Array(x.length), c = [];
185
+ for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); c.push(x.charCodeAt(i)); }
186
+ if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
187
+ //console.log('Send', c);
188
+ } else {
189
+ var b = new Uint8Array(x.length);
190
+ for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
191
+ if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
192
+ }
193
} else {
188
- var b = new Uint8Array(x.length);
189
- for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
190
- if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
194
+ //if (obj.debugmode == 1) { console.log('Send', x); }
195
+ if (obj.webRtcActive == true) { obj.webchannel.send(x); } else { obj.socket.send(x); }
196
}
192
- } else {
193
- //if (obj.debugmode == 1) { console.log('Send', x); }
194
- if (obj.webRtcActive == true) { obj.webchannel.send(x); } else { obj.socket.send(x); }
197
}
196
- }
198
+ } catch (ex) { }
199
}
200
201
obj.xxOnSocketClosed = function () {
public/scripts/amt-desktop-0.0.2.js
+1
@@ -8,6 +8,7 @@
8
var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
9
var obj = {};
10
obj.canvasid = divid;
11
+ obj.CanvasId = Q(divid);
12
obj.scrolldiv = scrolldiv;
13
obj.canvas = Q(divid).getContext("2d");
14
obj.protocol = 2; // KVM
views/default.handlebars
+226
-38
@@ -115,6 +115,12 @@
115
<input id=SearchInput type=text style=width:120px placeholder=Search onchange=onSearchInputChanged() onkeyup=onSearchInputChanged() autocomplete=off onfocus=onSearchFocus(1) onblur=onSearchFocus(0) />
116
<input type=checkbox id=HostnameCheckBox onclick=onHostnameCheckBox() /><span title="Show device hostnames">Hostname</span>
117
</div>
118
+ <div id=kvmListToolbar class=style14 style=height:100%;float:left>
119
+ <input type="button" onclick="connectAllKvmFunction();" value="Connect All" />
120
+ <input type="button" onclick="disconnectAllKvmFunction();" value="Disconnect All" />
121
+ <input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" />AutoConnect
122
+ <input type="button" onclick="showMultiDesktopSettings();" value="Settings" />
123
+ </div>
124
<div id=devMapToolbar class=style14 style=height:100%;float:left>
125
<input type=text id=mapSearchLocation placeholder="Search Location" onfocus=onMapSearchFocus(1) onblur=onMapSearchFocus(0) />
126
<input type=button value=Search title="Search for location" onclick=getSearchLocation() />
@@ -128,7 +134,8 @@
134
<select id=viewselect onchange=onDeviceViewChange()>
135
<option value=1>Columns</option>
136
<option value=2>List</option>
131
- <option id=viewselectmapoption value=3>Map</option>
137
+ <option value=3>Desktops</option>
138
+ <option id=viewselectmapoption value=4>Map</option>
139
</select>
140
</div>
141
<div style=float:right id=devListToolbarSort>
@@ -140,6 +147,15 @@
147
</select>
148
149
</div>
150
+ <div style=float:right id=devListToolbarSize>
151
+ Size
152
+ <select id=sizeselect onchange=onDeviceViewChange()>
153
+ <option value=0>Small</option>
154
+ <option value=1>Medium</option>
155
+ <option value=2>Large</option>
156
+ </select>
157
+
158
+ </div>
159
</div>
160
</div>
161
<div id=NoMeshesPanel style=display:none>
@@ -338,7 +354,9 @@
354
<tr id=deskarea3>
355
<td id=deskarea3x style="background:black;text-align:center;height:400px;position:relative">
356
<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>
341
- <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>
357
+ <div id="DeskParent">
358
+ <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>
359
+ </div>
360
</td>
361
</tr>
362
<tr id=deskarea4>
@@ -635,10 +653,12 @@
653
var nodeShortIdent = 0;
654
var desktop;
655
var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024 };
656
+ var multidesktopsettings = { quality: 30, scaling: 128 };
657
var terminal;
658
var files;
659
var debugLevel = {{{debuglevel}}};
660
var features = {{{features}}};
661
+ var multiDesktop = {};
662
var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}";
663
var amtScanResults = null;
664
var debugmode = false;
@@ -695,7 +715,8 @@
715
meshserver.Start();
716
717
// Setup page controls
698
- document.getElementById("sortselect").selectedIndex = sort = getstore("sort", 0);
718
+ Q('sortselect').selectedIndex = sort = getstore("sort", 0);
719
+ Q('sizeselect').selectedIndex = getstore("viewsize", 1);
720
Q('SearchInput').value = getstore("search", "");
721
showHostnames = (getstore("showHostnames", 0) == 1);
722
Q('HostnameCheckBox').checked = showHostnames;
@@ -723,8 +744,10 @@
744
setInterval(updateDeviceTimeline, 120000); // Check every 2 minutes
745
746
// Load desktop settings
726
- t = localStorage.getItem('desktopsettings');
747
+ var t = localStorage.getItem('desktopsettings');
748
if (t != null) { desktopsettings = JSON.parse(t); }
749
+ t = localStorage.getItem('multidesktopsettings');
750
+ if (t != null) { multidesktopsettings = JSON.parse(t); }
751
applyDesktopSettings();
752
753
// Mouse Scroll on desktop
@@ -1260,6 +1283,7 @@
1283
1284
function onDeviceViewChange() {
1285
putstore("deviceView", Q('viewselect').value);
1286
+ putstore("viewsize", Q('sizeselect').value);
1287
updateDevices();
1288
}
1289
@@ -1331,26 +1355,29 @@
1355
var deviceHeaderCount;
1356
var deviceHeaders = {};
1357
function updateDevices() {
1334
- var r = "", c = 0, current = null, count = 0, displayedMeshes = {}, view = Q('viewselect').value;
1335
- QV('xdevices', view < 3);
1336
- QV('xdevicesmap', view == 3);
1358
+ var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, view = Q('viewselect').value;
1359
+ QV('xdevices', view < 4);
1360
+ QV('xdevicesmap', view == 4);
1361
QV('devListToolbar', view < 3);
1338
- QV('devMapToolbar', view == 3);
1339
- QV('devListToolbarSort', view < 3);
1362
+ QV('kvmListToolbar', view == 3);
1363
+ QV('devMapToolbar', view == 4);
1364
+ QV('devListToolbarSort', view < 4);
1365
+ QV('devListToolbarSize', view == 3);
1366
QV('NoMeshesPanel', meshcount == 0);
1367
QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0));
1368
QV('devListToolbarSort', (meshcount != 0) && (nodes.length > 0));
1369
if ((meshcount == 0) || (nodes.length == 0)) { view = 1; }
1344
- if (view == 3) {
1370
+ if (view == 4) {
1371
setTimeout( function() { if (xxmap.map != null) { xxmap.map.updateSize(); } }, 200);
1372
// TODO
1373
} else {
1348
- // 3 wide or list view
1374
+ // 3 wide, list view or desktop view
1375
deviceHeaderId = 0;
1376
deviceHeaderCount = {};
1377
deviceHeaderTotal = 0;
1378
deviceHeaders = {};
1379
deviceHeadersTitles = {};
1380
+ var kvmDivs = [];
1381
1382
// Save the list of currently checked nodeid's
1383
var checkedNodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
@@ -1361,14 +1388,15 @@
1388
if (nodes[i].v == false) continue;
1389
var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
1390
if (meshlinks == null) continue;
1391
+ var meshrights = meshlinks.rights;
1392
+ if ((view == 3) && (mesh2.mtype == 1)) continue;
1393
if (sort == 0) {
1394
// Mesh header
1395
if (nodes[i].meshid != current) {
1396
deviceHeaderSet();
1397
var extra = '';
1398
if (meshes[nodes[i].meshid].mtype == 1) { extra = '<span class=devHeaderx>, Intel® AMT only</span>'; }
1370
- var meshrights = meshlinks.rights;
1371
- if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } r += '</tr></table>'; }
1399
+ if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
1400
r += '<div class=DevSt style=width:100%;padding-top:4px><span style=float:right>';
1401
r += getMeshActions(mesh2, meshrights);
1402
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 @@
1408
// Power header
1409
if (nodes[i].pwr !== current) {
1410
deviceHeaderSet();
1383
- if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } r += '</tr></table>'; }
1411
+ if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
1412
r += '<div class=DevSt style=width:100%;padding-top:4px><span>' + PowerStateStr2(nodes[i].pwr) + '</span><span id=DevxHeader' + deviceHeaderId + ' class="devHeaderx"></span></div>';
1413
current = nodes[i].pwr;
1414
c = 0;
@@ -1404,12 +1432,19 @@
1432
if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; }
1433
if (view == 1) {
1434
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>';
1407
- } else {
1435
+ } else if (view == 2) {
1436
r += '<tr><td><div id=devs class=bar18 style=height:18px;width:100%;font-size:medium>';
1437
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>';
1438
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>';
1439
r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
1440
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>';
1441
+ } else if ((view == 3) && (nodes[i].conn & 1) && ((meshrights & 8) != 0)) {
1442
+ 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)>';
1443
+ //r += '<input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox style=float:left>';
1444
+ r += '<div class="j' + icon + '" style=width:16px;float:left></div> ' + name + '</div>';
1445
+ 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>';
1446
+ r += '</div>';
1447
+ kvmDivs.push(nodes[i]._id);
1448
}
1449
1450
deviceHeaderTotal++;
@@ -1419,13 +1454,13 @@
1454
if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding
1455
1456
// Display all empty meshes, we need to do this because users can add devices to these at any time.
1422
- if (sort == 0 && Q('SearchInput').value == '') {
1457
+ if ((sort == 0) && (Q('SearchInput').value == '') && (view < 3)) {
1458
for (var i in meshes) {
1459
var mesh = meshes[i], meshlink = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
1460
if (meshlink != null) {
1461
var meshrights = meshlink.rights;
1462
if (displayedMeshes[mesh._id] == null) {
1428
- if (current != '') { r += '</tr></table>'; }
1463
+ if ((current != '') && (r != '')) { r += '</tr></table>'; }
1464
r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span style=float:right>';
1465
r += getMeshActions(mesh, meshrights);
1466
r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></td></tr><tr>';
@@ -1462,6 +1497,132 @@
1497
for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
1498
for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
1499
p1updateInfo();
1500
+
1501
+ // Take care of KVM surfaces in desktop view mode
1502
+ if (view == 3) {
1503
+ var vsize = [{x:180,y:101}, {x:302,y:169}, {x:454,y:255}][Q('sizeselect').selectedIndex];
1504
+ for (var i in multiDesktop) { multiDesktop[i].xxdelete = true; }
1505
+ for (var i in kvmDivs) {
1506
+ var id = kvmDivs[i], shortid = id.split('/')[2], desk = multiDesktop[id];
1507
+ if (desk != null) {
1508
+ // This device already has a canvas, use it.
1509
+ desk.m.CanvasId.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
1510
+ Q('xkvmid_' + shortid).appendChild(desk.m.CanvasId);
1511
+ delete desk.xxdelete;
1512
+ QH('skvmid_' + shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][((desk.m.State == null)?desk.m.state:desk.m.State)]);
1513
+ } else {
1514
+ var node = getNodeFromId(id);
1515
+ if ((desktopNode == node) && (desktop != null)) { // Check if the main desktop is this device, if it is, use that.
1516
+ // This device already has a canvas, use it.
1517
+ var c = desktop.m.CanvasId;
1518
+ c.setAttribute('id', 'kvmid_' + shortid);
1519
+ c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
1520
+ c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
1521
+ c.removeAttribute('onmousedown');
1522
+ c.removeAttribute('onmouseup');
1523
+ c.removeAttribute('onmousemove');
1524
+ Q('xkvmid_' + shortid).appendChild(c);
1525
+ QH('skvmid_' + shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][((desktop.m.State == null)?desktop.m.state:desktop.m.State)]);
1526
+ if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling); }
1527
+ desktop.shortid = shortid;
1528
+ desktop.onStateChanged = onMultiDesktopStateChange;
1529
+ multiDesktop[id] = desktop;
1530
+ desktop = desktopNode = currentNode = null;
1531
+ // Setup a replacement desktop
1532
+ 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>');
1533
+ } else {
1534
+ // This is a new device, create a canvas for it.
1535
+ var c = document.createElement('canvas');
1536
+ c.setAttribute('id', 'kvmid_' + shortid);
1537
+ c.setAttribute('width', 640);
1538
+ c.setAttribute('height', 200);
1539
+ c.setAttribute('oncontextmenu', 'return false');
1540
+ c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
1541
+ c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
1542
+ Q('xkvmid_' + shortid).appendChild(c);
1543
+ // Check if we need to auto-connect
1544
+ if (Q('autoConnectDesktopCheckbox').checked == true) { setTimeout(function() { connectMultiDesktop(node, 1); }, 100); }
1545
+ }
1546
+ }
1547
+ }
1548
+ for (var i in multiDesktop) {
1549
+ // If a device is no longer viewed, disconnect it.
1550
+ if (multiDesktop[i].xxdelete == true) { multiDesktop[i].Stop(); delete multiDesktop[i]; }
1551
+ }
1552
+ } else {
1553
+ disconnectAllKvmFunction();
1554
+ Q('autoConnectDesktopCheckbox').checked = false;
1555
+ }
1556
+
1557
+ }
1558
+ }
1559
+
1560
+ function toggleKvmDevice(nodeid) {
1561
+ var node = getNodeFromId(nodeid), mesh = meshes[node.meshid], meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
1562
+ if ((meshrights & 8) != 0) { // Requires remote control rights
1563
+ //var conn = 0;
1564
+ //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)
1565
+ if (node.conn & 1) { connectMultiDesktop(node, 1); }
1566
+ }
1567
+ }
1568
+
1569
+ function autoConnectDesktops() { if (Q('autoConnectDesktopCheckbox').checked == true) { connectAllKvmFunction(); } }
1570
+ function connectAllKvmFunction() { for (var i in nodes) { if (multiDesktop[nodes[i]._id] == null) { toggleKvmDevice(nodes[i]._id); } } }
1571
+ function disconnectAllKvmFunction() { for (var nodeid in multiDesktop) { multiDesktop[nodeid].Stop(); } multiDesktop = {}; }
1572
+ function onMultiDesktopStateChange(desk, state) { try { QH('skvmid_' + desk.shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][state]); } catch (ex) {} }
1573
+
1574
+ function showMultiDesktopSettings() {
1575
+ QV('d7amtkvm', false);
1576
+ QV('d7meshkvm', true);
1577
+ d7bitmapquality.value = multidesktopsettings.quality;
1578
+ d7bitmapscaling.value = multidesktopsettings.scaling;
1579
+ setDialogMode(7, "Remote Desktop Settings", 3, showMultiDesktopSettingsChanged);
1580
+ }
1581
+
1582
+ function showMultiDesktopSettingsChanged() {
1583
+ multidesktopsettings.quality = d7bitmapquality.value;
1584
+ multidesktopsettings.scaling = d7bitmapscaling.value;
1585
+ localStorage.setItem('multidesktopsettings', JSON.stringify(multidesktopsettings));
1586
+ // Make changes to all current connections
1587
+ for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(1,multidesktopsettings.quality,multidesktopsettings.scaling); }
1588
+ }
1589
+
1590
+ function connectMultiDesktop(node, contype) {
1591
+ var nodeid = node._id;
1592
+ var desk = multiDesktop[nodeid];
1593
+ if (desk == null) {
1594
+ if (contype == 2) {
1595
+ // Setup the Intel AMT remote desktop
1596
+ if ((node.intelamt.user == null) || (node.intelamt.user == '')) { return; }
1597
+ desk = CreateAmtRedirect(CreateAmtRemoteDesktop('kvmid_' + nodeid.split('/')[2]));
1598
+ desk.shortid = nodeid.split('/')[2];
1599
+ //desk.debugmode = debugmode;
1600
+ desk.onStateChanged = onMultiDesktopStateChange;
1601
+ desk.m.bpp = 1;
1602
+ desk.m.useZRLE = true;
1603
+ desk.m.showmouse = true;
1604
+ //desk.m.onScreenSizeChange = deskAdjust;
1605
+ desk.Start(nodeid, 16994, '*', '*', 0);
1606
+ desk.contype = 2;
1607
+ multiDesktop[nodeid] = desk;
1608
+ } else if (contype == 1) {
1609
+ // Setup the Mesh Agent remote desktop
1610
+ desk = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('kvmid_' + nodeid.split('/')[2]), serverPublicNamePort);
1611
+ desk.shortid = nodeid.split('/')[2];
1612
+ desk.attemptWebRTC = attemptWebRTC;
1613
+ desk.onStateChanged = onMultiDesktopStateChange;
1614
+ desk.m.CompressionLevel = multidesktopsettings.quality;
1615
+ desk.m.ScalingLevel = multidesktopsettings.scaling;
1616
+ //desk.m.onDisplayinfo = deskDisplayInfo;
1617
+ //desk.m.onScreenSizeChange = deskAdjust;
1618
+ desk.Start(nodeid);
1619
+ desk.contype = 1;
1620
+ multiDesktop[nodeid] = desk;
1621
+ }
1622
+ } else {
1623
+ // Disconnect and clean up the remote desktop
1624
+ desk.Stop();
1625
+ delete multiDesktop[nodeid];
1626
}
1627
}
1628
@@ -1546,8 +1707,9 @@
1707
function addCiraDeviceToMesh(meshid) {
1708
if (xxdialogMode) return;
1709
var mesh = meshes[meshid];
1549
- var meshidx = meshid.substring(5);
1550
- if (meshidx[0] == '/') meshidx = meshidx.substring(1);
1710
+
1711
+ // Replace non alphabetic characters (@ and $) with 'X' because MPS username cannot accept it.
1712
+ var meshidx = meshid.split('/')[2].replace(/\@/g, 'X').replace(/\$/g, 'X');
1713
1714
var y = '<select id=dlgAddCiraSel onclick=dlgAddCiraSelClick() style=width:230px><option value=0>MeshCommander Script</option><option value=1>Manual Username/Password</option>';
1715
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 @@
1763
function inviteAgentToMesh(meshid) {
1764
if (xxdialogMode) return;
1765
var mesh = meshes[meshid];
1604
- var meshidx = meshid.substring(5);
1605
- if (meshidx[0] == '/') meshidx = meshidx.substring(1);
1766
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 />";
1767
x += addHtmlValue('E-Mail', '<input id=agentInviteEmail style=width:240px onkeyup=validateAgentInvite()></input>');
1768
setDialogMode(2, "Invite Mesh Agent", 3, performAgentInvite, x, meshid);
@@ -1619,10 +1779,7 @@
1779
1780
function addAgentToMesh(meshid) {
1781
if (xxdialogMode) return;
1622
- var mesh = meshes[meshid];
1623
- var meshidx = meshid.substring(5);
1624
- if (meshidx[0] == '/') meshidx = meshidx.substring(1);
1625
- var x = "";
1782
+ var mesh = meshes[meshid], x = '';
1783
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>';
1784
1785
// Windows agent install
@@ -2459,8 +2616,7 @@
2616
}
2617
2618
function getNodeRights(nodeid) {
2462
- var node = getNodeFromId(nodeid);
2463
- var mesh = meshes[node.meshid];
2619
+ var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
2620
return mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
2621
}
2622
@@ -2471,6 +2627,7 @@
2627
var powerTimeline = null;
2628
function getCurrentNode() { return currentNode; };
2629
function gotoDevice(nodeid, panel, refresh) {
2630
+ //disconnectAllKvmFunction();
2631
var node = getNodeFromId(nodeid);
2632
var mesh = meshes[node.meshid];
2633
var meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
@@ -2607,7 +2764,6 @@
2764
Q('MainComputerImage').className = ((!node.conn) || (node.conn == 0)?'gray':'');
2765
2766
// Setup/Refresh the desktop tab
2610
- setupDesktop();
2767
setupTerminal();
2768
setupFiles();
2769
var consoleRights = ((meshrights & 16) != 0);
@@ -2640,6 +2796,7 @@
2796
// Request the power timeline
2797
if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { powerTimelineReq = currentNode._id; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
2798
}
2799
+ setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
2800
if (!panel) panel = 10;
2801
go(panel);
2802
}
@@ -2917,7 +3074,7 @@
3074
var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc'];
3075
function showEditNodeValueDialog(mode) {
3076
if (xxdialogMode) return;
2920
- var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:230px maxlength=32 onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
3077
+ var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:230px maxlength=64 onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
3078
setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode);
3079
var v = currentNode[showEditNodeValueDialog_modes2[mode]];
3080
if (v == null) v = '';
@@ -2945,7 +3102,34 @@
3102
var desktopNode;
3103
function setupDesktop() {
3104
// Setup the remote desktop
2948
- if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); delete desktop; desktop = null; }
3105
+ if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); delete desktop; desktopNode = null; desktop = null; }
3106
+
3107
+ // If the device desktop is already connected in multi-desktop, use that.
3108
+ if ((desktopNode != currentNode) || (desktop == null)) {
3109
+ var xdesk = multiDesktop[currentNode._id];
3110
+ if (xdesk != null) {
3111
+ // This device already has a canvas, use it.
3112
+ QH('DeskParent', '');
3113
+ var c = xdesk.m.CanvasId;
3114
+ c.setAttribute('id', 'Desk');
3115
+ c.setAttribute('style', 'width:100%;-ms-touch-action:none;margin-left:0px');
3116
+ c.setAttribute('onmousedown', 'dmousedown(event)');
3117
+ c.setAttribute('onmouseup', 'dmouseup(event)');
3118
+ c.setAttribute('onmousemove', 'dmousemove(event)');
3119
+ c.removeAttribute('onclick');
3120
+ Q('DeskParent').appendChild(c);
3121
+ desktop = xdesk;
3122
+ if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling); }
3123
+ desktop.onStateChanged = onDesktopStateChange;
3124
+ desktopNode = currentNode;
3125
+ onDesktopStateChange(desktop, desktop.State);
3126
+ delete multiDesktop[currentNode._id];
3127
+ } else {
3128
+ // Device is not already connected, just setup a blank canvas
3129
+ 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>');
3130
+ desktopNode = currentNode;
3131
+ }
3132
+ }
3133
desktopNode = currentNode;
3134
updateDesktopButtons();
3135
@@ -2955,22 +3139,22 @@
3139
3140
// Show and enable the right buttons
3141
function updateDesktopButtons() {
2958
- var mesh = meshes[desktopNode.meshid];
3142
+ var mesh = meshes[currentNode.meshid];
3143
var deskState = ((desktop != null) && (desktop.state != 0));
3144
3145
// Show the right buttons
3146
QV('disconnectbutton1span', (deskState == true));
3147
QV('connectbutton1span', (deskState == false) && (mesh.mtype == 2));
2964
- QV('connectbutton1hspan', (deskState == false) && (desktopNode.intelamt != null && ((desktopNode.intelamt.ver != null) || (mesh.mtype == 1))));
3148
+ QV('connectbutton1hspan', (deskState == false) && (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
3149
3150
// Show the right settings
2967
- QV('d7amtkvm', (desktopNode.intelamt != null && ((desktopNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == false) || (desktop.contype == 2)));
3151
+ QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == false) || (desktop.contype == 2)));
3152
QV('d7meshkvm', (mesh.mtype == 2) && ((deskState == false) || (desktop.contype == 1)));
3153
3154
// Enable buttons
2971
- var online = ((desktopNode.conn & 1) != 0); // If Agent (1) connected, enable Terminal
3155
+ var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable Terminal
3156
QE('connectbutton1', online);
2973
- var hwonline = ((desktopNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
3157
+ var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
3158
QE('connectbutton1h', hwonline);
3159
}
3160
@@ -2980,6 +3164,7 @@
3164
3165
function connectDesktop(e, contype) {
3166
if (desktop == null) {
3167
+ desktopNode = currentNode;
3168
if (contype == 2) {
3169
// Setup the Intel AMT remote desktop
3170
if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
@@ -3010,7 +3195,7 @@
3195
// Disconnect and clean up the remote desktop
3196
desktop.Stop();
3197
delete desktop;
3013
- desktop = null;
3198
+ desktopNode = desktop = null;
3199
}
3200
}
3201
@@ -3029,7 +3214,7 @@
3214
// Disconnect and clean up the remote desktop
3215
desktop.Stop();
3216
delete desktop;
3032
- desktop = null;
3217
+ desktopNode = desktop = null;
3218
QV('DeskFocus', false);
3219
QV('termdisplays', false);
3220
deskFocusBtn.value = 'All Focus';
@@ -3044,6 +3229,8 @@
3229
}
3230
3231
function showDesktopSettings() {
3232
+ applyDesktopSettings();
3233
+ updateDesktopButtons();
3234
setDialogMode(7, "Remote Desktop Settings", 3, showDesktopSettingsChanged);
3235
}
3236
@@ -3074,7 +3261,7 @@
3261
d7showfocus.checked = desktopsettings.showfocus;
3262
d7showcursor.checked = desktopsettings.showmouse;
3263
d7bitmapquality.value = 40; // Default value
3077
- if (ops.indexOf(desktopsettings.quality) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
3264
+ if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
3265
d7bitmapscaling.value = desktopsettings.scaling;
3266
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus));
3267
}
@@ -4925,6 +5112,7 @@
5112
QS('MainDevConsole').backgroundColor = ((x == 15) ? "#003366" : "#808080");
5113
QV('MeshSubMenuSpan', x >= 20 && x < 30);
5114
QS('MeshGeneral').backgroundColor = ((x == 20) ? "#003366" : "#808080");
5115
+ if (x == 1) updateDevices();
5116
}
5117
5118
// Generic methods