Server connection fix.
Ylian Saint-Hilaire committed
Aug 13, 2019 at 13:55 UTC
fd8a3c79a0c71f27d46089779cbc9c35b8299717
5 files changed
+43
-8439
MeshCentralServer.njsproj
+2
@@ -267,6 +267,8 @@
267
<Content Include="views\default-mobile.handlebars" />
268
<Content Include="views\default.handlebars" />
269
<Content Include="views\download.handlebars" />
270
+ <Content Include="views\error404-mobile.handlebars" />
271
+ <Content Include="views\error404.handlebars" />
272
<Content Include="views\login-min.handlebars" />
273
<Content Include="views\login-mobile-min.handlebars" />
274
<Content Include="views\login-mobile.handlebars" />
meshagent.js
+2
-2
@@ -389,13 +389,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
389
// Perform the hash signature using older swarm server certificate
390
parent.parent.certificateOperations.acceleratorPerformSignature(1, msg.substring(2) + obj.nonce, null, function (tag, signature) {
391
// Send back our certificate + signature
392
- obj2.sendBinary(common.ShortToStr(2) + common.ShortToStr(parent.swarmCertificateAsn1.length) + parent.swarmCertificateAsn1 + signature); // Command 2, certificate + signature
392
+ obj.sendBinary(common.ShortToStr(2) + common.ShortToStr(parent.swarmCertificateAsn1.length) + parent.swarmCertificateAsn1 + signature); // Command 2, certificate + signature
393
});
394
} else {
395
// Perform the hash signature using the server agent certificate
396
parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, null, function (tag, signature) {
397
// Send back our certificate + signature
398
- obj2.sendBinary(common.ShortToStr(2) + common.ShortToStr(parent.agentCertificateAsn1.length) + parent.agentCertificateAsn1 + signature); // Command 2, certificate + signature
398
+ obj.sendBinary(common.ShortToStr(2) + common.ShortToStr(parent.agentCertificateAsn1.length) + parent.agentCertificateAsn1 + signature); // Command 2, certificate + signature
399
});
400
}
401
}
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.3.9-r",
3
+ "version": "0.3.9-s",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
public/player.htm
+38
-3
@@ -10,6 +10,7 @@
10
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
11
<script type="text/javascript" src="scripts/agent-desktop-0.0.2.js"></script>
12
<script type="text/javascript" src="scripts/amt-desktop-0.0.2.js"></script>
13
+ <script type="text/javascript" src="scripts/amt-terminal-0.0.2.js"></script>
14
<script type="text/javascript" src="scripts/zlib.js"></script>
15
<script type="text/javascript" src="scripts/zlib-inflate.js"></script>
16
<script type="text/javascript" src="scripts/zlib-adler32.js"></script>
@@ -30,13 +31,16 @@
31
<div id=deskarea2 style="">
32
<div class="areaProgress"><div id="progressbar" style=""></div></div>
33
</div>
33
- <div id=deskarea3x style="max-height:calc(100vh - 54px);height:calc(100vh - 54px);">
34
+ <div id=deskarea3x style="max-height:calc(100vh - 54px);height:calc(100vh - 54px);position:relative">
35
<div id="bigok" style="display:none;left:calc((100vh / 2))"><b>✓</b></div>
36
<div id="bigfail" style="display:none;left:calc((100vh / 2))"><b>✗</b></div>
37
<div id="metadatadiv" style="padding:20px;color:lightgrey;text-align:left;display:none"></div>
38
<div id=DeskParent onclick="togglePause()">
39
<canvas id=Desk width=640 height=480></canvas>
40
</div>
41
+ <div id=TermParent onclick="togglePause()" style="margin:0;overflow:hidden;height:100px;left:0;position:absolute;right:0;top:0;background-color:red">
42
+ <pre id=Term style="background-color:blue"></pre>
43
+ </div>
44
<div id=p11DeskConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=clearConsoleMsg()></div>
45
</div>
46
<div id=deskarea4 class="areaFoot">
@@ -176,7 +180,21 @@
180
else if (p == 101) { p = 'Intel® AMT Redirection'; }
181
x += addInfoNoEsc('Protocol', p);
182
}
179
- if (recFileMetadata.protocol == 2) {
183
+ console.log('desk');
184
+ QV('DeskParent', true);
185
+ QV('TermParent', false);
186
+ if (recFileMetadata.protocol == 1) {
187
+ // MeshCentral remote terminal
188
+ recFileProtocol = 1;
189
+ x += '<br /><br /><span style=color:gray>Press [space] to play/pause.</span>';
190
+ QE('PlayButton', true);
191
+ QE('PauseButton', false);
192
+ QE('RestartButton', false);
193
+ recFileStartTime = recFileLastTime = time;
194
+ agentTerminal = CreateAmtRemoteTerminal('Term', {});
195
+ agentTerminal.State = 3;
196
+ }
197
+ else if (recFileMetadata.protocol == 2) {
198
// MeshCentral remote desktop
199
recFileProtocol = 2;
200
x += '<br /><br /><span style=color:gray>Press [space] to play/pause.</span>';
@@ -237,7 +255,10 @@
255
256
if ((type == 2) && flagBinary && !flagUser) {
257
// Device --> User data
240
- if (recFileProtocol == 2) {
258
+ if (recFileProtocol == 1) {
259
+ // MeshCentral Terminal
260
+ agentTerminal.ProcessData(data);
261
+ } else if (recFileProtocol == 2) {
262
// MeshCentral Remote Desktop
263
agentDesktop.ProcessData(data);
264
} else if (recFileProtocol == 101) {
@@ -276,6 +297,10 @@
297
QH('timespan', '00:00:00');
298
QV('metadatadiv', true);
299
QH('metadatadiv', '<span style=\"font-family:Arial,Helvetica Neue,Helvetica,sans-serif;font-size:28px\">MeshCentral Session Player</span><br /><br /><span style=color:gray>Drag & drop a .mcrec file or click "Open File..."</span>');
300
+ QH('Term', '');
301
+ console.log('desk');
302
+ QV('DeskParent', true);
303
+ QV('TermParent', false);
304
}
305
306
function ondrop(e) {
@@ -359,6 +384,11 @@
384
QE('PlayButton', false);
385
QE('PauseButton', true);
386
QE('RestartButton', false);
387
+ if (recFileProtocol == 1) {
388
+ console.log('term');
389
+ QV('DeskParent', false);
390
+ QV('TermParent', true);
391
+ }
392
readNextBlock(processBlock);
393
}
394
@@ -389,6 +419,10 @@
419
QE('RestartButton', false);
420
QS('progressbar').width = '0px';
421
QH('timespan', '00:00:00');
422
+ QH('Term', '');
423
+ console.log('desk');
424
+ QV('DeskParent', true);
425
+ QV('TermParent', false);
426
if (agentDesktop) {
427
agentDesktop.Canvas.clearRect(0, 0, agentDesktop.CanvasId.width, agentDesktop.CanvasId.height);
428
} else if (amtDesktop) {
@@ -409,6 +443,7 @@
443
}
444
445
function deskAdjust() {
446
+ return;
447
var parentH = Q('DeskParent').clientHeight, parentW = Q('DeskParent').clientWidth;
448
var deskH = Q('Desk').height, deskW = Q('Desk').width;
449
views/default-old.handlebars
deleted
-8433
@@ -1,8433 +0,0 @@
1
-<!DOCTYPE html>
2
-<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
3
-<head>
4
- <meta http-equiv="X-UA-Compatible" content="IE=edge" />
5
- <meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
6
- <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
7
- <meta name="apple-mobile-web-app-capable" content="yes" />
8
- <meta name="format-detection" content="telephone=no" />
9
- <link rel="shortcut icon" type="image/x-icon" href="{{{domainurl}}}favicon.ico" />
10
- <link keeplink=1 type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS" />
11
- <link type="text/css" href="styles/ol.css" media="screen" rel="stylesheet" title="CSS" />
12
- <link type="text/css" href="styles/ol3-contextmenu.min.css" media="screen" rel="stylesheet" title="CSS" />
13
- <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
14
- <script type="text/javascript" src="scripts/meshcentral.js"></script>
15
- <script type="text/javascript" src="scripts/amt-0.2.0.js"></script>
16
- <script type="text/javascript" src="scripts/amt-wsman-0.2.0.js"></script>
17
- <script type="text/javascript" src="scripts/amt-desktop-0.0.2.js"></script>
18
- <script type="text/javascript" src="scripts/amt-terminal-0.0.2.js"></script>
19
- <script type="text/javascript" src="scripts/zlib.js"></script>
20
- <script type="text/javascript" src="scripts/zlib-inflate.js"></script>
21
- <script type="text/javascript" src="scripts/zlib-adler32.js"></script>
22
- <script type="text/javascript" src="scripts/zlib-crc32.js"></script>
23
- <script type="text/javascript" src="scripts/amt-redir-ws-0.1.0.js"></script>
24
- <script type="text/javascript" src="scripts/amt-wsman-ws-0.2.0.js"></script>
25
- <script type="text/javascript" src="scripts/agent-redir-ws-0.1.0.js"></script>
26
- <script type="text/javascript" src="scripts/agent-redir-rtc-0.1.0.js"></script>
27
- <script type="text/javascript" src="scripts/agent-desktop-0.0.2.js"></script>
28
- <script type="text/javascript" src="scripts/qrcode.min.js"></script>
29
- <script keeplink=1 type="text/javascript" src="scripts/u2f-api.js"></script>
30
- <script keeplink=1 type="text/javascript" src="scripts/charts.js"></script>
31
- <script keeplink=1 type="text/javascript" src="scripts/filesaver.js"></script>
32
- <script keeplink=1 type="text/javascript" src="scripts/ol.js"></script>
33
- <script keeplink=1 type="text/javascript" src="scripts/ol3-contextmenu.js"></script>
34
- <title>{{{title}}}</title>
35
-</head>
36
-<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" oncontextmenu="handleContextMenu(event)" style="display:none;min-width:495px">
37
- <!-- right click menu -->
38
- <div id="contextMenu" class="contextMenu noselect" style="display:none">
39
- <div id="cxinfo" class="cmtext" onclick="cmaction(1,event)"><b>Information</b></div>
40
- <div id="cxdesktop" class="cmtext" onclick="cmaction(3,event)">Desktop</div>
41
- <div id="cxterminal" class="cmtext" onclick="cmaction(2,event)">Terminal</div>
42
- <div id="cxfiles" class="cmtext" onclick="cmaction(4,event)">Files</div>
43
- <div id="cxevents" class="cmtext" onclick="cmaction(5,event)">Events</div>
44
- <div id="cxconsole" class="cmtext" onclick="cmaction(6,event)">Console</div>
45
- <hr id="cxmgroupsplit" />
46
- <div id="cxmdesktop" class="cmtext" onclick="cmaction(7,event)" style="display:none">Multi-Desktop</div>
47
- </div>
48
- <div id="meshContextMenu" class="contextMenu,noselect" style="display: none; min-width: 0px">
49
- <div id="cxselectall" class="cmtext" onclick="cmmeshaction(1,event)">Select All</div>
50
- <div id="cxselectnone" class="cmtext" onclick="cmmeshaction(2,event)">Select None</div>
51
- <hr id="cxmgroupsplit2" style="display:none" />
52
- <div id="cxmmdesktop" class="cmtext" style="display:none" onclick="cmmeshaction(3,event)">Multi-Desktop</div>
53
- </div>
54
- <!-- main page -->
55
- <div id=container>
56
- <div id="notifiyBox" class="notifiyBox" style="display:none"></div>
57
- <div id=masthead class=noselect>
58
- <div class="title">{{{title}}}</div>
59
- <div class="title2">{{{title2}}}</div>
60
- <div style="float:right">
61
- <div id=notificationCount onclick="clickNotificationIcon()" class="unselectable" style="display: none;" title="Click to view current notifications">0</div>
62
- </div>
63
- <p id="logoutControl">{{{logoutControl}}}<span id=idleTimeoutNotify style="color:yellow"></span></p>
64
- </div>
65
- <div id="page_leftbar">
66
- <div style="height:16px"></div>
67
- <div id=LeftMenuMyDevices tabindex=0 class="lbbutton lbbuttonsel" title="My Devices" onclick=go(1) onkeypress="if (event.key=='Enter') { go(1); }">
68
- <div class="lb2"></div>
69
- </div>
70
- <div id=LeftMenuMyAccount tabindex=0 class="lbbutton" title="My Account" onclick=go(2) onkeypress="if (event.key=='Enter') { go(2); }">
71
- <div class="lb1"></div>
72
- </div>
73
- <div id=LeftMenuMyEvents tabindex=0 class="lbbutton" title="My Events" onclick=go(3) onkeypress="if (event.key=='Enter') { go(3); }">
74
- <div class="lb3"></div>
75
- </div>
76
- <div id=LeftMenuMyFiles tabindex=0 class="lbbutton" style="display:none" title="My Files" onclick=go(5) onkeypress="if (event.key=='Enter') { go(5); }">
77
- <div class="lb4"></div>
78
- </div>
79
- <div id=LeftMenuMyUsers tabindex=0 class="lbbutton" style="display:none" title="My Users" onclick=go(4) onkeypress="if (event.key=='Enter') { go(4); }">
80
- <div class="lb5"></div>
81
- </div>
82
- <div id=LeftMenuMyServer tabindex=0 class="lbbutton" style="display:none" title="My Server" onclick=go(6) onkeypress="if (event.key=='Enter') { go(6); }">
83
- <div class="lb6"></div>
84
- </div>
85
- </div>
86
- <div id=topbar class=noselect>
87
- <div>
88
- <div style="position:relative">
89
- <div tabindex=0 id=uiMenuButton title="User interface selection" onclick="showUserInterfaceSelectMenu()" onkeypress="if (event.key == 'Enter') showUserInterfaceSelectMenu()">♦
90
- <div id=uiMenu style="display:none">
91
- <div tabindex=0 id=uiViewButton1 class=uiSelector onclick=userInterfaceSelectMenu(1) title="Left bar interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(1)"><div class="uiSelector1"></div></div>
92
- <div tabindex=0 id=uiViewButton2 class=uiSelector onclick=userInterfaceSelectMenu(2) title="Top bar interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(2)"><div class="uiSelector2"></div></div>
93
- <div tabindex=0 id=uiViewButton3 class=uiSelector onclick=userInterfaceSelectMenu(3) title="Fixed width interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(3)"><div class="uiSelector3"></div></div>
94
- <div tabindex=0 id=uiViewButton4 class=uiSelector onclick=toggleNightMode() title="Toggle night mode" onkeypress="if (event.key == 'Enter') toggleNightMode()"><div class="uiSelector4"></div></div>
95
- </div>
96
- </div>
97
- <table id=MainMenuSpan cellpadding=0 cellspacing=0 class=style1>
98
- <tr>
99
- <td tabindex=0 id=MainMenuMyDevices class="topbar_td style3x" onclick=go(1) onkeypress="if (event.key == 'Enter') go(1)">My Devices</td>
100
- <td tabindex=0 id=MainMenuMyAccount class="topbar_td style3x" onclick=go(2) onkeypress="if (event.key == 'Enter') go(2)">My Account</td>
101
- <td tabindex=0 id=MainMenuMyEvents class="topbar_td style3x" onclick=go(3) onkeypress="if (event.key == 'Enter') go(3)">My Events</td>
102
- <td tabindex=0 id=MainMenuMyFiles class="topbar_td style3x" onclick=go(5) onkeypress="if (event.key == 'Enter') go(5)">My Files</td>
103
- <td tabindex=0 id=MainMenuMyUsers class="topbar_td style3x" onclick=go(4) onkeypress="if (event.key == 'Enter') go(4)">My Users</td>
104
- <td tabindex=0 id=MainMenuMyServer class="topbar_td style3x" onclick=go(6) onkeypress="if (event.key == 'Enter') go(6)">My Server</td>
105
- <td class="topbar_td_end style3"> </td>
106
- </tr>
107
- </table>
108
- <div id=MainSubMenuSpan style="display:none">
109
- <table id=MainSubMenu cellpadding=0 cellspacing=0 class=style1>
110
- <tr>
111
- <td tabindex=0 id=MainDev class="topbar_td style3x" onclick=go(10) onkeypress="if (event.key == 'Enter') go(10)">General</td>
112
- <td tabindex=0 id=MainDevDesktop class="topbar_td style3x" onclick=go(11) onkeypress="if (event.key == 'Enter') go(11)">Desktop</td>
113
- <td tabindex=0 id=MainDevTerminal class="topbar_td style3x" onclick=go(12) onkeypress="if (event.key == 'Enter') go(12)">Terminal</td>
114
- <td tabindex=0 id=MainDevFiles class="topbar_td style3x" onclick=go(13) onkeypress="if (event.key == 'Enter') go(13)">Files</td>
115
- <td tabindex=0 id=MainDevEvents class="topbar_td style3x" onclick=go(16) onkeypress="if (event.key == 'Enter') go(16)">Events</td>
116
- <td tabindex=0 id=MainDevAmt class="topbar_td style3x" onclick=go(14) onkeypress="if (event.key == 'Enter') go(14)">Intel® AMT</td>
117
- <td tabindex=0 id=MainDevConsole class="topbar_td style3x" onclick=go(15) onkeypress="if (event.key == 'Enter') go(15)">Console</td>
118
- <td class="topbar_td_end style3"> </td>
119
- </tr>
120
- </table>
121
- </div>
122
- <div id=MeshSubMenuSpan style="display:none">
123
- <table id=MeshSubMenu cellpadding=0 cellspacing=0 class=style1>
124
- <tr>
125
- <td tabindex=0 id=MeshGeneral class="topbar_td style3x" onclick=go(20) onkeypress="if (event.key == 'Enter') go(20)">General</td>
126
- <td class="topbar_td_end style3"> </td>
127
- </tr>
128
- </table>
129
- </div>
130
- <div id=UserSubMenuSpan style="display:none">
131
- <table id=UserSubMenu cellpadding=0 cellspacing=0 class=style1>
132
- <tr>
133
- <td tabindex=0 id=UserGeneral class="topbar_td style3x" onclick=go(30) onkeypress="if (event.key == 'Enter') go(30)">General</td>
134
- <td tabindex=0 id=UserEvents class="topbar_td style3x" onclick=go(31) onkeypress="if (event.key == 'Enter') go(31)">Events</td>
135
- <td class="topbar_td_end style3"> </td>
136
- </tr>
137
- </table>
138
- </div>
139
- <div id=ServerSubMenuSpan style="display:none">
140
- <table id=ServerSubMenu cellpadding=0 cellspacing=0 class=style1>
141
- <tr>
142
- <td tabindex=0 id=ServerGeneral class="topbar_td style3x" onclick=go(6) onkeypress="if (event.key == 'Enter') go(6)">General</td>
143
- <td tabindex=0 id=ServerStats class="topbar_td style3x" onclick=go(40) onkeypress="if (event.key == 'Enter') go(40)">Stats</td>
144
- <td tabindex=0 id=ServerConsole class="topbar_td style3x" onclick=go(115) onkeypress="if (event.key == 'Enter') go(115)">Console</td>
145
- <td class="topbar_td_end style3"> </td>
146
- </tr>
147
- </table>
148
- </div>
149
- <div id=UserDummyMenuSpan>
150
- <table id=UserDummyMenu cellpadding=0 cellspacing=0 class=style1>
151
- <tr><td class=style3 style=""> </td></tr>
152
- </table>
153
- </div>
154
- </div>
155
- </div>
156
- </div>
157
- <div id="column_l">
158
- <div id=p0 style="display:none">
159
- <div id=p0message><span id=p0span>Server disconnected</span>, <href onclick=reload() style=cursor:pointer><u>click to reconnect</u></href>.</div>
160
- </div>
161
- <div id=p1 style="display:none">
162
- <div style="display:none" id="devListToolbarViewIcons">
163
- <div tabindex=0 id=devViewButton1 class=viewSelector onclick=onDeviceViewChange(1) onkeypress="if (event.key=='Enter') { onDeviceViewChange(1); }" title="Columns"><div class="viewSelector2"></div></div>
164
- <div tabindex=0 id=devViewButton2 class=viewSelector onclick=onDeviceViewChange(2) onkeypress="if (event.key == 'Enter') { onDeviceViewChange(2); }" title="List"><div class="viewSelector1"></div></div>
165
- <div tabindex=0 id=devViewButton3 class=viewSelector onclick=onDeviceViewChange(3) onkeypress="if (event.key == 'Enter') { onDeviceViewChange(3); }" title="Desktops"><div class="viewSelector3"></div></div>
166
- <div tabindex=0 id=devViewButton4 class=viewSelector onclick=onDeviceViewChange(4) onkeypress="if (event.key == 'Enter') { onDeviceViewChange(4); }" title="Map"><div class="viewSelector4"></div></div>
167
- </div><div><h1>My Devices</h1></div>
168
- <table id="devListToolbarSpan" class="noselect">
169
- <tr>
170
- <td class=h1></td>
171
- <td id=devListToolbar class=style14 style="display:none">
172
- <input type="button" id="SelectAllButton" onclick="selectallButtonFunction();" value="Select All" />
173
- <input type=button id=GroupActionButton disabled="disabled" value="Group Action" onclick=groupActionFunction() />
174
- <input id=SearchInput type=text placeholder=Filter onchange=masterUpdate(5) onkeyup=masterUpdate(5) autocomplete=off onfocus=onSearchFocus(1) onblur=onSearchFocus(0) />
175
- <label><input type=checkbox id=RealNameCheckBox onclick=onRealNameCheckBox() /><span title="Show devices operating system name">OS Name</span></label>
176
- </td>
177
- <td id=kvmListToolbar class=style14 style="display:none">
178
- <input type="button" onclick="connectAllKvmFunction()" value="Connect All" />
179
- <input type="button" onclick="disconnectAllKvmFunction()" value="Disconnect All" />
180
- <label><input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" title="Automatic connect" />Auto </label>
181
- <input type="button" onclick="showMultiDesktopSettings()" value="Settings" />
182
- </td>
183
- <td id=devMapToolbar class=style14 style="display:none">
184
- <input type=text id=mapSearchLocation placeholder="Search Location" onfocus=onMapSearchFocus(1) onblur=onMapSearchFocus(0) />
185
- <input type=button value=Search title="Search for location" onclick=getSearchLocation() />
186
- <input type=button id=refreshmap title="Reset map view" value=Reset onclick=refreshMap(false,true) />
187
- </td>
188
- <td class="auto-style1" style=height:100%>
189
- <div style="display:none" id=devListToolbarView>
190
- View
191
- <select id=viewselect onchange=onDeviceViewChange()>
192
- <option value=1>Columns</option>
193
- <option value=2>List</option>
194
- <option value=3>Desktops</option>
195
- <option id=viewselectmapoption value=4>Map</option>
196
- </select>
197
- </div>
198
- <div style="display:none" id=devListToolbarSort>
199
- Sort
200
- <select id=sortselect onchange=masterUpdate(6)>
201
- <option>Group</option>
202
- <option>Power</option>
203
- <option>Device</option>
204
- <option>Tags</option>
205
- </select>
206
-
207
- </div>
208
- <div style="display:none" id=devListToolbarSize>
209
- Size
210
- <select id=sizeselect onchange=onDeviceViewChange()>
211
- <option value=0>Small</option>
212
- <option value=1>Medium</option>
213
- <option value=2>Large</option>
214
- </select>
215
-
216
- </div>
217
- </td>
218
- <td class=h2></td>
219
- </tr>
220
- </table>
221
- <div id=NoMeshesPanel style="display:none">
222
- <table>
223
- <tr>
224
- <td valign="top" style="width: 50px">
225
- <img src="images/info.png" />
226
- </td>
227
- <td>
228
- <div id="getStarted1">To get started, <a href=# onclick="return account_createMesh()"><strong>click here to create a device group</strong></a>.</div>
229
- <div id="getStarted2">No device groups.</div>
230
- </td>
231
- </tr>
232
- </table>
233
- </div>
234
- <div id="xdevices" class="noselect" style="display:none"></div>
235
- <div id="xdevicesmap" style="display:none">
236
- <div id=xmapSearchResultsDlg style="display:none">
237
- <div id=xmapSearchResultsBck>
238
- <div id=xmapSearchClose onclick=mapCloseSearchWindow()><b>X</b></div>
239
- <div style=padding:5px>Location Results</div>
240
- <div style=width:100%;margin:6px></div>
241
- </div>
242
- <div id=xmapSearchResults style=margin:6px></div>
243
- </div>
244
- </div>
245
- <div id="xmap-info-window"></div>
246
- </div>
247
- <div id=p2 style="display:none">
248
- <h1>My Account</h1>
249
- <img id="p2AccountImage" alt="" src="images/clipboard-128.png"/>
250
- <div id="p2AccountSecurity" style="display:none">
251
- <p><strong>Account security</strong></p>
252
- <div style="margin-left:25px">
253
- <div id="manageAuthApp"><div class="p2AccountActions"><span id="authAppSetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageAuthApp()">Manage authenticator app</a><br /></span></div>
254
- <div id="manageHardwareOtp"><div class="p2AccountActions"><span id="authKeySetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageHardwareOtp(0)">Manage security keys</a><br /></span></div>
255
- <div id="manageOtp"><div class="p2AccountActions"><span id="authCodesSetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageOtp(0)">Manage backup codes</a><br /></span></div>
256
- </div>
257
- </div>
258
- <div id="p2AccountActions">
259
- <p><strong>Account actions</strong></p>
260
- <p class="mL">
261
- <span id="verifyEmailId" style="display:none"><a href=# onclick="return account_showVerifyEmail()">Verify email</a><br /></span>
262
- <span id="accountEnableNotificationsSpan" style="display:none"><a href=# onclick="return account_enableNotifications()">Enable web notifications</a><br /></span>
263
- <a href=# onclick="return account_showAccountNotifySettings()">Notification Settings</a><br />
264
- <span id="accountChangeEmailAddressSpan" style="display:none"><a href=# onclick="return account_showChangeEmail()">Change email address</a><br /></span>
265
- <a href=# onclick="return account_showChangePassword()">Change password</a><span id="p2nextPasswordUpdateTime"></span><br />
266
- <a href=# onclick="return account_showDeleteAccount()">Delete account</a><br />
267
- </p>
268
- <br style=clear:both />
269
- </div>
270
- <strong>Device Groups</strong>
271
- <span id="p2createMeshLink1">( <a href=# onclick="return account_createMesh()" class="newMeshBtn"> New</a> )</span>
272
- <br /><br />
273
- <div id=p2meshes></div>
274
- <div id=p2noMeshFound style="display:none">No device groups.<span id="p2createMeshLink2"> <a href=# onclick="return account_createMesh()"><strong>Get started here!</strong></a></span></div>
275
- <br style=clear:both />
276
- </div>
277
- <div id=p3 style="display:none">
278
- <h1>My Events</h1>
279
- <table class="pTable">
280
- <tr>
281
- <td class="h1"></td>
282
- <td> <input id="p2deleteall" type=button onclick=showDeleteAllEventsDialog() style="display:none" value="Delete All..." /></td>
283
- <td class="auto-style1">
284
- Show
285
- <select id=p3limitdropdown onchange=refreshEvents()>
286
- <option value=60>Last 60</option>
287
- <option value=120>Last 120</option>
288
- <option value=250>Last 250</option>
289
- <option value=500>Last 500</option>
290
- <option value=1000>Last 1000</option>
291
- </select>
292
- <a href=# onclick=p3showDownloadEventsDialog()><img src=images/link4.png height=10 width=10 title="Download Events" style=cursor:pointer></a>
293
- </td>
294
- <td class="h2"></td>
295
- </tr>
296
- </table>
297
- <div id=p3events style=""></div>
298
- </div>
299
- <div id=p4 style="display:none">
300
- <h1>My Users</h1>
301
- <table class="pTable">
302
- <tr>
303
- <td class="h1"></td>
304
- <td class="style14">
305
- <div style="float:right">
306
- <input type=button onclick=showUserBroadcastDialog() style=margin-right:6px value="Broadcast" />
307
- <a href=# onclick=p4downloadUserInfo()><img style="cursor:pointer" title="Download user information" src="images/link4.png" /></a>
308
- <a href=# onclick=p4batchAccountCreate()><img id=p4UserBatchCreate style="cursor:pointer;display:none" title="Batch create many user accounts" src="images/link6.png" /></a>
309
- </div>
310
- <div>
311
- <input id=UserNewAccountButton type=button style=margin-left:6px onclick=showCreateNewAccountDialog() value="New Account..." />
312
- <input id=UserSearchInput type=text style=width:120px;margin-left:6px placeholder=Filter onchange=onUserSearchInputChanged() onkeyup=onUserSearchInputChanged() autocomplete=off onfocus=onUserSearchFocus(1) onblur=onUserSearchFocus(0) />
313
- </div>
314
- </td>
315
- <td class="h2"></td>
316
- </tr>
317
- </table>
318
- <div id="p3users"></div>
319
- </div>
320
- <div id=p5 style="display:none">
321
- <h1>My Files</h1>
322
- <table id="p5toolbar" cellpadding="0" cellspacing="0">
323
- <tr>
324
- <td id="p5filehead" valign=bottom>
325
- <div id="p5rightOfButtons"></div>
326
- <div>
327
- <input type=button id=p5FolderUp disabled="disabled" onclick="return p5folderup();" value="Up" />
328
- <input type=button id=p5SelectAllButton disabled="disabled" onclick="p5selectallfile();" value="Select All" />
329
- <input type=button id=p5RenameFileButton disabled="disabled" value="Rename" onclick="p5renamefile();" />
330
- <input type=button id=p5DeleteFileButton disabled="disabled" value="Delete" onclick="p5deletefile();" />
331
- <input type=button id=p5NewFolderButton disabled="disabled" value="New Folder" onclick="p5createfolder();" />
332
- <input type=button id=p5UploadButton disabled="disabled" value="Upload" onclick="p5uploadFile()" />
333
- <input type=button id=p5CutButton disabled="disabled" value="Cut" onclick="p5copyFile(1)" />
334
- <input type=button id=p5CopyButton disabled="disabled" value="Copy" onclick="p5copyFile(0)" />
335
- <input type=button id=p5PasteButton disabled="disabled" value="Paste" onclick="p5pasteFile()" />
336
- </div>
337
- </td>
338
- </tr>
339
- <tr>
340
- <td id="p5filesubhead">
341
- <div style=float:right>
342
- <select id=p5sortdropdown onchange=updateFiles()>
343
- <option value="1" selected="selected">Sort by name</option>
344
- <option value="2">Sort by size</option>
345
- <option value="3">Sort by date</option>
346
- <option value="4">Descend by name</option>
347
- <option value="5">Descend by size</option>
348
- <option value="6">Descend by date</option>
349
- </select>
350
- </div>
351
- <div> <span id="p5currentpath"></span></div>
352
- </td>
353
- </tr>
354
- </table>
355
- <div id="p5filetable">
356
- <!--
357
- <form id=p5fileCatchAll method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame>
358
- <input type=file id=p5fileCatchAllInput name=files style="position:absolute;left:0;width:100%;top:0;bottom:0;opacity:0;display:none" onchange="p5fileCatchAllInputChanged(event)" />
359
- <input id=p5fileDragLink2 name="link" style="display:none" />
360
- <input type=submit id=p5fileCatchAllSubmit style="display:none" />
361
- </form>
362
- -->
363
- <div id="p5PublicShare" style=""><div>These files are shared publicly, click "link" to get public url.</div></div>
364
- <div id="bigok" style="display:none"><b>✓</b></div>
365
- <div id="bigfail" style="display:none"><b>✗</b></div>
366
- <span id="p5files"></span>
367
- </div>
368
- <table id="p5toolbarBottom" style=width:100% cellpadding=0 cellspacing=0>
369
- <tr><td class=style6> <span id="p5bottomstatus"></span></td></tr>
370
- </table>
371
- </div>
372
- <div id=p6 style="display:none">
373
- <img id=MainMeshImage src="serverpic.ashx">
374
- <h1>My Server</h1>
375
- <div id="p2ServerActions">
376
- <p><strong>Server actions</strong></p>
377
- <div class="mL">
378
- <div id="p2ServerActionsBackup"><a href="{{{domainurl}}}backup.zip" rel="noreferrer noopener" target="_blank">Download server backup</a></div>
379
- <div id="p2ServerActionsRestore"><a href=# onclick="return server_showRestoreDlg()">Restore server with backup</a></div>
380
- <div id="p2ServerActionsVersion"><a href=# onclick="return server_showVersionDlg()">Check server version</a></div>
381
- <div id="p2ServerActionsErrors"><a href=# onclick="return server_showErrorsDlg()">Show server error log</a></div>
382
- </div>
383
- </div>
384
- <br /><strong>Server Statistics</strong><br /><br />
385
- <div id="serverStats">
386
- <div id="serverCpuChartView" style="display:none">
387
- <div class="chartViewCanvas"><canvas id="serverCpuChart"></canvas></div>
388
- <div class="chartViewText" id="serverCpuChartText"></div>
389
- </div>
390
- <div id="serverMemoryChartView" style="display:none">
391
- <div class="chartViewCanvas"><canvas id="serverMemoryChart"></canvas></div>
392
- <div class="chartViewText" id="serverMemoryChartText"></div>
393
- </div><br /><br />
394
- <div id="serverStatsTable"></div>
395
- </div>
396
- </div>
397
- <div id=p10 style="display:none">
398
- <table style="width:100%" cellpadding="0" cellspacing="0">
399
- <tr>
400
- <td style=width:auto valign=top>
401
- <div id=p10title>
402
- <div id="p10BackButton"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
403
- <h1>General - <span id=p10deviceName></span></h1>
404
- </div>
405
- <div id=p10html></div>
406
- </td>
407
- <td style=width:20px></td>
408
- <td style=width:200px>
409
- <a href=# onclick=p10showiconselector()><img id=MainComputerImage></a>
410
- <div id=MainComputerState></div>
411
- </td>
412
- </tr>
413
- </table><br>
414
- <div id=p10html2></div>
415
- <div id=p10html3></div>
416
- </div>
417
- <div id=p11 class="noselect" style="display:none">
418
- <div id="p11title">
419
- <div id=p11deviceNameHeader>
420
- <div id="p11BackButton"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
421
- <div id="devListToolbarViewIcons"><div class="viewSelector" onclick=deskToggleFull(event) title="Full Screen. Hold shift to browser full screen."><div class="viewSelector5"></div></div></div>
422
- <h1>Desktop - <span id=p11deviceName></span></h1>
423
- </div>
424
- </div>
425
- <div id="p11warning" onclick="showFeaturesDlg()">
426
- <div class="icon2"></div>
427
- <div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p11warninga">, click here to enable it.</span></div>
428
- </div>
429
- <div id="p11warning2" onclick="showPowerActionDlg()">
430
- <div class="icon2"></div>
431
- <div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
432
- </div>
433
- <div id=deskarea0 cellpadding=0 cellspacing=0>
434
- <div id=deskarea1 class="areaHead">
435
- <div class="toright2">
436
- <span id="p11power"></span>
437
- <div class='deskareaicon' title="Toggle View Mode" onclick="toggleAspectRatio(1)">⇲</div>
438
- <div class='deskareaicon' title="Rotate Left" onclick="drotate(-1)">↺</div>
439
- <div class='deskareaicon' title="Rotate Right" onclick="drotate(1)">↻</div>
440
- <input id="deskFocusBtn" type="button" title="Toggle focus mode, when active only the region around the mouse is updated" onkeypress="return false" onkeydown="return false" value="Focus All" onclick="deskToggleFocus()" style="margin-right:3px;display:none">
441
- <input id="deskSaveBtn" type="button" title="Save a screenshot of the remote desktop" onkeypress="return false" onkeydown="return false" value="Save..." onclick=deskSaveImage() class="mR">
442
- <input id="deskActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() class="mR" />
443
- <input id="deskActionsSettings" type="button" value="Settings..." title="Edit remote desktop settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" class="mR">
444
- <input type="button" title="Change the power state of the remote machine" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="display:none">
445
- </div>
446
- <div>
447
- <div id="idx_deskFullBtn2" onclick=deskToggleFull(event)> ✖</div>
448
- <input type="button" id="autoconnectbutton1" value="AutoConnect" onclick=autoConnectDesktop(event) onkeypress="return false" onkeydown="return false" style="display:none">
449
- <span id=connectbutton1span><input type=button id=connectbutton1 value="Connect" onclick=connectDesktop(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
450
- <span id=connectbutton1hspan> <input type=button id=connectbutton1h value="HW Connect" onclick=connectDesktop(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
451
- <span id=disconnectbutton1span> <input type=button id=disconnectbutton1 value="Disconnect" onclick=connectDesktop(event,0) onkeypress="return false" onkeydown="return false"></span>
452
- <span id="deskstatus">Disconnected</span>
453
- </div>
454
- </div>
455
- <div id=deskarea2 style="">
456
- <div class="areaProgress"><div id="progressbar" style=""></div></div>
457
- </div>
458
- <div id=deskarea3x>
459
- <div id=DeskFocus oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></div>
460
- <div id=DeskParent>
461
- <canvas id=Desk width=640 height=480 oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event) onmousewheel=dmousewheel(event)></canvas>
462
- </div>
463
- <div id=DeskTools>
464
- <a id=DeskToolsRefreshButton style="" onclick="refreshDeskTools()">Refresh</a>
465
- <div id=DeskToolsBar>Processes</div>
466
- <div id=deskToolsArea>
467
- <div id=deskToolsHeader>
468
- <a class="colmn1" title="Sort by process id" onclick=sortProcess(0)>PID</a>
469
- <a class="colmn2" title="Sort by name" onclick=sortProcess(1)>Name</a></div>
470
- <div id="DeskToolsProcesses" style=""></div>
471
- </div>
472
- </div>
473
- <div id=p11DeskConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p11clearConsoleMsg()></div>
474
- </div>
475
- <div id=deskarea4 class="areaFoot">
476
- <div class="toright2">
477
- <select id=termdisplays style="display:none" onchange=deskSetDisplay(event) onkeypress="return false" onkeydown="return false"></select>
478
- <input id=DeskToolsButton type=button value=Tools title="Toggle tools view" onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()">
479
- <span id=DeskChatButton class="deskarea" title="Open chat window to this computer"><img src='images/icon-chat.png' onclick=deviceChat() height=16 width=16 style=padding-top:2px /></span>
480
- <span id=DeskNotifyButton title="Display a notification on the remote computer"><img src='images/icon-notify.png' onclick=deviceToastFunction() height=16 width=16 style=padding-top:2px /></span>
481
- <span id=DeskOpenWebButton title="Open a web address on remote computer"><img src='images/icon-url2.png' onclick=deviceUrlFunction() height=16 width=16 style=padding-top:2px /></span>
482
- </div>
483
- <div>
484
- <select id="deskkeys">
485
- <option value=10>Ctrl+Alt+Del</option>
486
- <option value=5>Win</option>
487
- <option value=0>Win+Down</option>
488
- <option value=1>Win+Up</option>
489
- <option value=2>Win+L</option>
490
- <option value=3>Win+M</option>
491
- <option value=4>Shift+Win+M</option>
492
- <option value=6>Win+R</option>
493
- <option value=7>Alt-F4</option>
494
- <option value=8>Ctrl-W</option>
495
- <option value=9>Alt-Tab</option>
496
- </select>
497
- <input id="DeskWD" type=button value="Send" onkeypress="return false" onkeydown="return false" onclick="deskSendKeys()">
498
- <input id="DeskClip" style="" type="button" value="Clipboard" onkeypress="return false" onkeydown="return false" onclick="showDeskClip()">
499
- <label><span id="DeskControlSpan" title="Toggle mouse and keyboard input"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false" onclick="toggleKvmControl()">Input</span></label>
500
- </div>
501
- </div>
502
- </div>
503
- </div>
504
- <div id=p12 style="display:none">
505
- <div id="p12title">
506
- <div id="p12BackButton"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
507
- <h1>Terminal - <span id=p12deviceName></span></h1>
508
- </div>
509
- <div id="p12warning" onclick=showFeaturesDlg()>
510
- <div class="icon2"></div>
511
- <div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p12warninga">, click here to enable it.</span></div>
512
- </div>
513
- <div id="p12warning2" onclick=showPowerActionDlg()>
514
- <div class="icon2"></div>
515
- <div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
516
- </div>
517
- <div id=termTable style="position:relative">
518
- <table style="width:100%" cellpadding=0 cellspacing=0>
519
- <tr>
520
- <td class="areaHead">
521
- <div class="toright2">
522
- <input id="termActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction()/>
523
- </div>
524
- <div>
525
- <input type="button" id="autoconnectbutton2" value="AutoConnect" onclick=autoConnectTerminal(event) onkeypress="return false" onkeydown="return false" style="display:none">
526
- <span id="connectbutton2span"><input type="button" id="connectbutton2" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
527
- <span id="connectbutton2hspan"> <input type="button" id="connectbutton2h" value="HW Connect" onclick=connectTerminal(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
528
- <span id="disconnectbutton2span"> <input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false"></span>
529
- <span id="termstatus">Disconnected</span><span id="termtitle"></span>
530
- </div>
531
- </td>
532
- </tr>
533
- <tr>
534
- <td>
535
- <div class="areaProgress"><div id="termprogressbar" style=""></div></div>
536
- </td>
537
- </tr>
538
- <tr>
539
- <td id="termarea3x">
540
- <pre id="Term"></pre>
541
- </td>
542
- </tr>
543
- <tr>
544
- <td class="areaFoot">
545
- <div class="toright2">
546
- <span id="terminalSettingsButtons" style="display:none">
547
- <input id="id_tcrbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="CR+LF" title="Toggle what the return key will send" onclick="termToggleCr()">
548
- <input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx()">
549
- <input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()">
550
- </span>
551
- <span id="terminalSizeDropDown">
552
- <select id="termSizeList" onkeypress="return false"><option value="1">80x25</option><option value="2">100x30</option><option value="3" selected>Auto</option></select>
553
- </span>
554
- <select id="specialkeylist" onkeypress="return false"></select>
555
- <input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />
556
- </div>
557
- <div>
558
-
559
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')" />
560
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')" />
561
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')" />
562
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Backspace" onclick="termSendKey(8,'bsbutton')" />
563
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()" />
564
- </div>
565
- </td>
566
- </tr>
567
- </table>
568
- <div id=p12TermConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:45px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p12clearConsoleMsg()></div>
569
- </div>
570
- </div>
571
- <div id=p13 style="display:none">
572
- <div id="p13title">
573
- <div id="p13BackButton" style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
574
- <h1>Files - <span id=p13deviceName></span></h1>
575
- </div>
576
- <table id="p13toolbar" cellpadding="0" cellspacing="0">
577
- <tr>
578
- <td class="areaHead">
579
- <div class="toright2">
580
- <input id="filesActionsBtn" type=button title="Perform power actions on the device" value=Actions onclick=deviceActionFunction() />
581
- </div>
582
- <div>
583
- <input id=p13AutoConnect value="AutoConnect" onclick=autoConnectFiles(event) type="button" style="display:none">
584
- <input id=p13Connect value="Connect" onclick=connectFiles(event) type="button">
585
- <span id=p13Status>Disconnected</span>
586
- </div>
587
- </td>
588
- </tr>
589
- <tr>
590
- <td class="areaHead2" valign=bottom>
591
- <div id="p13rightOfButtons" class="toright2"></div>
592
- <div>
593
- <input type=button id=p13FolderUp disabled="disabled" onclick="p13folderup()" value="Up" />
594
- <input type=button id=p13SelectAllButton disabled="disabled" onclick="p13selectallfile()" value="Select All" />
595
- <input type=button id=p13RenameFileButton disabled="disabled" value="Rename" onclick="p13renamefile()" />
596
- <input type=button id=p13DeleteFileButton disabled="disabled" value="Delete" onclick="p13deletefile()" />
597
- <input type=button id=p13NewFolderButton disabled="disabled" value="New Folder" onclick="p13createfolder()" />
598
- <input type=button id=p13UploadButton disabled="disabled" value="Upload" onclick="p13uploadFile()" />
599
- <input type=button id=p13CutButton disabled="disabled" value="Cut" onclick="p13copyFile(1)" />
600
- <input type=button id=p13CopyButton disabled="disabled" value="Copy" onclick="p13copyFile(0)" />
601
- <input type=button id=p13PasteButton disabled="disabled" value="Paste" onclick="p13pasteFile()" />
602
- <input type=button id=p13RefreshButton disabled="disabled" value="Refresh" onclick="p13folderup(9999)" />
603
- </div>
604
- </td>
605
- </tr>
606
- <tr>
607
- <td class="areaHead3">
608
- <div class="toright2">
609
- <select id=p13sortdropdown onchange=p13updateFiles()>
610
- <option value=1 selected="selected">Sort by name</option>
611
- <option value=2>Sort by size</option>
612
- <option value=3>Sort by date</option>
613
- <option value=4>Descend by name</option>
614
- <option value=5>Descend by size</option>
615
- <option value=6>Descend by date</option>
616
- </select>
617
- </div>
618
- <div> <span id="p13currentpath"></span></div>
619
- </td>
620
- </tr>
621
- </table>
622
- <div id=p13FilesConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:165px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p13clearConsoleMsg()></div>
623
- <div id="p13filetable" style="">
624
- <div id="p13bigok" style="display:none"><b>✓</b></div>
625
- <div id="p13bigfail" style="display:none"><b>✗</b></div>
626
- <span id="p13files"></span>
627
- </div>
628
- <table id="p13toolbarBottom" cellpadding=0 cellspacing=0>
629
- <tr><td class=style6> <span id="p13bottomstatus"></span></td></tr>
630
- </table>
631
- </div>
632
- <div id=p14 style="display:none">
633
- <div id="p14title">
634
- <div id="p14BackButton" style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
635
- <div id="devListToolbarViewIcons"><div class="viewSelector" onclick=deskToggleFull(event) title="Full Screen. Hold shift to browser full screen."><div class="viewSelector5"></div></div></div>
636
- <h1>Intel® AMT - <span id=p14deviceName></span></h1>
637
- </div>
638
- <iframe id=p14iframe src="{{{domainurl}}}commander.htm"></iframe>
639
- </div>
640
- <div id=p15 style="display:none">
641
- <div id="p15title">
642
- <div id="p15BackButton" style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
643
- <h1><span id=p15deviceName></span></h1>
644
- </div>
645
- <table id="consoleTable" cellpadding=0 cellspacing=0>
646
- <tr>
647
- <td class="areaHead">
648
- <div class="toright2">
649
- <div id=p15coreName title="Information about current core running on this agent"></div>
650
- <input type=button id=p15uploadCore value="Agent Action" onclick=p15uploadCore(event) title="Change the agent Java Script code module" />
651
- <img onclick=p15downloadConsoleText() style="cursor:pointer;margin-top:6px" title="Download console text" src="images/link4.png" />
652
- </div>
653
- <div id="p15statetext"></div>
654
- </td>
655
- </tr>
656
- <tr>
657
- <td>
658
- <div class="areaProgress"><div id="consoleprogressbar" style=""></div></div>
659
- </td>
660
- </tr>
661
- <tr>
662
- <td id=p15agentConsole>
663
- <pre id=p15agentConsoleText></pre>
664
- </td>
665
- </tr>
666
- <tr>
667
- <td class="areaFoot">
668
- <table style="width:100%">
669
- <tr>
670
- <td style="width:99%">
671
- <input id=p15consoleText style=width:100% onkeyup=p15consoleSend(event) onfocus=onConsoleFocus(1) onblur=onConsoleFocus(0) />
672
- </td>
673
- <td> </td>
674
- <td style="width:1%"><input id="id_p15consoleClear" type="button" class="bottombutton" value="Clear" onclick="p15consoleClear()"></td>
675
- </tr>
676
- </table>
677
- </td>
678
- </tr>
679
- </table>
680
- </div>
681
- <div id=p16 style="display:none">
682
- <div id="p16title">
683
- <div id="p16BackButton" style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
684
- <h1>Events - <span id=p16deviceName></span></h1>
685
- </div>
686
- <table class="pTable">
687
- <tr>
688
- <td class="h1"></td>
689
- <td> <input type=button onclick=refreshDeviceEvents() value="Refresh" /></td>
690
- <td class="auto-style1">
691
- Show
692
- <select id=p16limitdropdown onchange=refreshDeviceEvents()>
693
- <option value=60>Last 60</option>
694
- <option value=120>Last 120</option>
695
- <option value=250>Last 250</option>
696
- <option value=500>Last 500</option>
697
- <option value=1000>Last 1000</option>
698
- </select>
699
- </td>
700
- <td class="h2"></td>
701
- </tr>
702
- </table>
703
- <div id=p16events></div>
704
- </div>
705
- <div id=p20 style="display:none">
706
- <picture id=MainMeshImage style=border-width:0px;height:200px;width:200px;float:right>
707
- <source type="image/webp" width=200 height=200 srcset="images/webp/mesh-256.webp">
708
- <img alt="" width=200 height=200 src=images/mesh-256.png />
709
- </picture>
710
- <div style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
711
- <h1>General - <span id=p20meshName></span></h1>
712
- <p id=p20info></p>
713
- </div>
714
- <div id=p30 style="display:none">
715
- <table style="width:100%" cellpadding="0" cellspacing="0">
716
- <tr>
717
- <td style=width:auto valign=top>
718
- <div id="p30title">
719
- <div style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
720
- <h1>General - <span id=p30userName></span></h1>
721
- </div>
722
- <div id=p30html></div>
723
- </td>
724
- <td style=width:20px></td>
725
- <td style=width:200px>
726
- <picture id=MainUserImage style=border-width:0px;height:200px;width:200px;float:right>
727
- <source type="image/webp" width=200 height=200 srcset="images/webp/user-256.webp">
728
- <img alt="" width=200 height=200 src=images/user-256.png />
729
- </picture>
730
- <div style="width:100%;text-align:center"><strong><span id=MainUserState></span></strong></div>
731
- </td>
732
- </tr>
733
- </table><br>
734
- <div id=p30html2></div>
735
- <div id=p30html3></div>
736
- </div>
737
- <div id=p31 style="display:none">
738
- <div style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
739
- <h1>Events - <span id=p31userName></span></h1>
740
- <table class="pTable">
741
- <tr>
742
- <td class="h1"></td>
743
- <td> <input type=button onclick=refreshUsersEvents() value="Refresh" /></td>
744
- <td class="auto-style1">
745
- Show
746
- <select id=p31limitdropdown onchange=refreshUsersEvents()>
747
- <option value=60>Last 60</option>
748
- <option value=120>Last 120</option>
749
- <option value=250>Last 250</option>
750
- <option value=500>Last 500</option>
751
- <option value=1000>Last 1000</option>
752
- </select>
753
- </td>
754
- <td class="h2"></td>
755
- </tr>
756
- </table>
757
- <div id=p31events></div>
758
- </div>
759
- <div id=p40 style="display:none;">
760
- <h1>My Server Stats</h1>
761
- <div class="areaHead">
762
- <div class="toright2">
763
- <select id=p40type onchange=updateServerTimelineStats()>
764
- <option value=0>Connections</option>
765
- <option value=1>Memory</option>
766
- </select>
767
- <select id=p40time onchange=updateServerTimelineHours()>
768
- <option value=3>Last 3 hours</option>
769
- <option value=8>Last 8 hours</option>
770
- <option value=24>Last day</option>
771
- <option value=168>Last week</option>
772
- <option value=720>Last 30 days</option>
773
- </select>
774
- <img src=images/link4.png height=10 width=10 title="Download data points (.csv)" style=cursor:pointer onclick=p40downloadEvents()>
775
- </div>
776
- <div>
777
- <input value="Refresh" type="button" onclick="refreshServerTimelineStats()" />
778
- <label><input id=p40log type="checkbox" onclick="updateServerTimelineHours()" />Log-X</label>
779
-</div>
780
- </div>
781
- <canvas id=serverMainStats style=""></canvas>
782
- </div>
783
- <br id="column_l_bottomgap" />
784
- </div>
785
- <div id="footer">
786
- <div class="footer1">{{{footer}}}</div>
787
- <div class="footer2">
788
- <a id="verifyEmailId2" style="display:none" href=# onclick="account_showVerifyEmail()">Verify Email</a>
789
- <a href=terms>Terms & Privacy</a>
790
- </div>
791
- </div>
792
- <div id=dialog class="noselect" style="display:none">
793
- <div id=dialogHeader>
794
- <div tabindex=0 id=id_dialogclose onclick=setDialogMode() onkeypress="if (event.key == 'Enter') setDialogMode()">✖</div>
795
- <div id=id_dialogtitle></div>
796
- </div>
797
- <div id=dialogBody>
798
- <div id=dialog1>
799
- <div id=id_dialogMessage style=""></div>
800
- </div>
801
- <div id=dialog2 style="">
802
- <div id=id_dialogOptions></div>
803
- </div>
804
- <div id=dialog3 style="">
805
- <div id=d3upload>
806
- <div>File Selection</div>
807
- <select id=d3uploadMode onchange=d3modechange()>
808
- <option value=1>Local file upload</option>
809
- <option value=2>Server file selection</option>
810
- </select>
811
- </div>
812
- <div id=d3localmode style="display:none">
813
- <div>Upload File</div>
814
- <form id=d3localmodeform method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame>
815
- <input type=text id=d3attrib name=attrib style="display:none" />
816
- <input type=file id=d3localFile name=files onchange=d3setActions() />
817
- <input type=submit id=d3submit style="display:none" />
818
- </form>
819
- </div>
820
- <div id=d3servermode>
821
- <div id=d3serveraction valign=bottom>
822
- <input type=button id=p3FolderUp disabled="disabled" onclick=d3folderup() value="Up" />
823
- </div>
824
- <div id=d3serverfiles></div>
825
- </div>
826
- </div>
827
- <div id=dialog7 style="">
828
- <div id="d7meshkvm">
829
- <h4>Agent Remote Desktop</h4>
830
- <div>
831
- <div>Quality</div>
832
- <select id="d7bitmapquality" dir="rtl"></select>
833
- </div>
834
- <div>
835
- <div>Scaling</div>
836
- <select id="d7bitmapscaling" style="" dir="rtl">
837
- <option selected=selected value=1024>100%</option>
838
- <option value=896>87.5%</option>
839
- <option value=768>75%</option>
840
- <option value=640>62.5%</option>
841
- <option value=512>50%</option>
842
- <option value=384>37.5%</option>
843
- <option value=256>25%</option>
844
- <option value=128>12.5%</option>
845
- </select>
846
- </div>
847
- <div>
848
- <div>Frame rate</div>
849
- <select id="d7framelimiter" dir="rtl">
850
- <option selected=selected value=50>Fast</option>
851
- <option value=100>Medium</option>
852
- <option value=400>Slow</option>
853
- <option value=1000>Very slow</option>
854
- </select>
855
- </div>
856
- </div>
857
- <div id="d7amtkvm">
858
- <h4>Intel® AMT Hardware KVM</h4>
859
- <div>
860
- <div>Image Encoding</div>
861
- <select id="d7desktopmode">
862
- <option value="1">RLE8, Fastest</option>
863
- <option value="2">RLE16, Recommended</option>
864
- <option value="3">RAW8, Slow</option>
865
- <option value="4">RAW16, Very Slow</option>
866
- </select>
867
- </div>
868
- <div>
869
- <div>Other Settings</div>
870
- <div id="d7otherset" style="display:block">
871
- <label style="display:block"><input type="checkbox" id="d7showfocus">Show Focus Tool</label>
872
- <label style="display:block"><input type="checkbox" id="d7showcursor">Show Local Mouse Cursor</label>
873
- <label style="display:block"><input type="checkbox" id="d7localKeyMap">Local Keyboard Map</label>
874
- </div>
875
- </div>
876
- </div>
877
- </div>
878
- </div>
879
- <div id="idx_dlgButtonBar">
880
- <input id="idx_dlgCancelButton" type="button" value="Cancel" style="" onclick="dialogclose(0)">
881
- <input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)">
882
- <div><input id="idx_dlgDeleteButton" type="button" value="Delete" style="display:none" onclick="dialogclose(2)"></div>
883
- </div>
884
- </div>
885
- <iframe name="fileUploadFrame" style="display:none"></iframe>
886
- <form style="display:none" method=post action=uploadfile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p5fileDragName name="name"><input id=p5fileDragSize name="size"><input id=p5fileDragType name="type"><input id=p5fileDragData name="data"><input id=p5fileDragLink name="link"><input type=submit id=p5loginSubmit2 style="display:none" /></form>
887
- <form style="display:none" method=post action=uploadnodefile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p13fileDragName name="name"><input id=p13fileDragSize name="size"><input id=p13fileDragType name="type"><input id=p13fileDragData name="data"><input id=p13fileDragLink name="link"><input type=submit id=p13loginSubmit2 style="display:none" /></form>
888
- <audio id="chimes"><source src="sounds/chimes.mp3" type="audio/mp3"></audio>
889
- </div>
890
- <script type="text/javascript">
891
- 'use strict';
892
-
893
- // Process server-side web state
894
- var webState = "{{{webstate}}}";
895
- if (webState != "") { webState = JSON.parse(decodeURIComponent(webState)); }
896
- for (var i in webState) { localStorage.setItem(i, webState[i]); }
897
- //localStorage.clear();
898
-
899
- var args;
900
- var autoReconnect = true;
901
- var powerStatetable = ['', 'Powered', 'Sleep', 'Sleep', 'Sleep', 'Hibernating', 'Power off', 'Present'];
902
- var StatusStrs = ['Disconnected', 'Connecting...', 'Setup...', 'Connected', 'Intel® AMT Connected'];
903
- var sort = 0;
904
- var searchFocus = 0;
905
- var mapSearchFocus = 0;
906
- var userSearchFocus = 0;
907
- var consoleFocus = 0;
908
- var showRealNames = false;
909
- var meshserver = null;
910
- var meshes = {};
911
- var meshcount = 0;
912
- var nodes = null;
913
- var filetree = {};
914
- var userinfo = null;
915
- var serverinfo = null;
916
- var events = [];
917
- var users = null;
918
- var wssessions = null;
919
- var nodeShortIdent = 0;
920
- var desktop;
921
- var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 50, localkeymap: false };
922
- var multidesktopsettings = { quality: 20, scaling: 128, framerate: 1000 };
923
- var terminal;
924
- var files;
925
- var debugLevel = parseInt("{{{debuglevel}}}");
926
- var features = parseInt("{{{features}}}");
927
- var sessionTime = parseInt("{{{sessiontime}}}");
928
- var domain = "{{{domain}}}";
929
- var domainUrl = "{{{domainurl}}}";
930
- var authCookie = "{{{authCookie}}}";
931
- var authCookieRenewTimer = null;
932
- var multiDesktop = {};
933
- var multiDesktopFilter = null;
934
- var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}";
935
- var amtScanResults = null;
936
- var debugmode = 0;
937
- var clickOnce = (((features & 256) != 0) && detectClickOnce());
938
- var attemptWebRTC = ((features & 128) != 0);
939
- var passRequirements = "{{{passRequirements}}}";
940
- if (passRequirements != "") { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
941
- var deskAspectRatio = 0;
942
- try { deskAspectRatio = parseInt(getstore('deskAspectRatio', '0')); } catch (ex) { }
943
- var uiMode = parseInt(getstore('uiMode', 1));
944
- var webPageStackMenu = false;
945
- var webPageFullScreen = true;
946
- var nightMode = (getstore('_nightMode', '0') == '1');
947
- var sessionActivity = Date.now();
948
-
949
- // Console Message Display Timers
950
- var p11DeskConsoleMsgTimer = null;
951
- var p12TermConsoleMsgTimer = null;
952
- var p13FilesConsoleMsgTimer = null;
953
-
954
- function startup() {
955
- if ((features & 32) == 0) {
956
- // Guard against other site's top frames (web bugs).
957
- var loc = null;
958
- try { loc = top.location.toString().toLowerCase(); } catch (e) { }
959
- if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
960
- }
961
-
962
- // Check if we are in debug mode
963
- args = parseUriArgs();
964
- debugmode = args.debug;
965
- if (args.webrtc != null) { attemptWebRTC = (args.webrtc == 1); }
966
- QV('p13AutoConnect', debugmode); // Files
967
- QV('autoconnectbutton2', debugmode); // Terminal
968
- QV('autoconnectbutton1', debugmode); // Desktop
969
- //QV('DeskClip', debugmode); // Clipboard feature, not completed so show in in debug mode only.
970
-
971
- if (nightMode) { QC('body').add('night'); }
972
- toggleFullScreen();
973
-
974
- // Setup page visuals
975
- if (args.hide) {
976
- var hide = parseInt(args.hide);
977
- QV('masthead', !(hide & 1));
978
- QV('topbar', !(hide & 2));
979
- QV('footer', !(hide & 4));
980
- QV('p10title', !(hide & 8));
981
- QV('p11title', !(hide & 8));
982
- QV('p12title', !(hide & 8));
983
- QV('p13title', !(hide & 8));
984
- QV('p14title', !(hide & 8));
985
- QV('p15title', !(hide & 8));
986
- QV('p16title', !(hide & 8));
987
- //if (hide & 16) {
988
- // QV('page_leftbar', false);
989
- // QS('page_content').left = '0px';
990
- //}
991
-
992
- // Fix the main grid to zero-height elements we want to hide.
993
- QS('container')['grid-template-rows'] = ((hide & 1) ? '0' : '66') + 'px ' + ((hide & 2) ? '0' : '24') + 'px auto ' + ((hide & 4) ? '0' : '45') + 'px';
994
- QS('container')['-ms-grid-rows'] = ((hide & 1) ? '0' : '66') + 'px ' + ((hide & 2) ? '0' : '24') + 'px auto ' + ((hide & 4) ? '0' : '45') + 'px';
995
-
996
- // Adjust height of remote desktop, files and Intel AMT
997
- var xh = (((hide & 1) ? 0 : 66) + ((hide & 2) ? 0 : 24) + ((hide & 4) ? 0 : 45) + ((hide & 8) ? 0 : 60)); // 0 to 195
998
- QS('p3users')['max-height'] = 'calc(100vh - ' + (124 + xh) + 'px)';
999
- QS('p3events')['height'] = 'calc(100vh - ' + (124 + xh) + 'px)';
1000
- QS('deskarea3x')['height'] = 'calc(100vh - ' + (75 + xh) + 'px)';
1001
- QS('deskarea3x')['max-height'] = 'calc(100vh - ' + (75 + xh) + 'px)';
1002
- QS('p5filetable')['height'] = 'calc(100vh - ' + (160 + xh) + 'px)';
1003
- QS('p13filetable')['height'] = 'calc(100vh - ' + (124 + xh) + 'px)';
1004
- QS('serverMainStats')['height'] = 'calc(100vh - ' + (110 + xh) + 'px)';
1005
- QS('serverMainStats')['max-height'] = 'calc(100vh - ' + (110 + xh) + 'px)';
1006
- QS('xdevices')['max-height'] = 'calc(100vh - ' + (124 + xh) + 'px)';
1007
- QS('xdevicesmap')['max-height'] = 'calc(100vh - ' + (124 + xh) + 'px)';
1008
- QS('p15agentConsole')['height'] = 'calc(100vh - ' + (84 + xh) + 'px)';
1009
- QS('p15agentConsole')['max-height'] = 'calc(100vh - ' + (84 + xh) + 'px)';
1010
- QS('p15agentConsoleText')['height'] = 'calc(100vh - ' + (81 + xh) + 'px)';
1011
- QS('p15agentConsoleText')['max-height'] = 'calc(100vh - ' + (81 + xh) + 'px)';
1012
- }
1013
-
1014
- // We are looking at a single device, remove all the back buttons
1015
- if ('{{currentNode}}' != '') {
1016
- QV('p10BackButton', false);
1017
- QV('p11BackButton', false);
1018
- QV('p12BackButton', false);
1019
- QV('p13BackButton', false);
1020
- QV('p14BackButton', false);
1021
- QV('p15BackButton', false);
1022
- QV('p16BackButton', false);
1023
- }
1024
- p1updateInfo();
1025
-
1026
- // Setup the context menu
1027
- document.onclick = function (e) { hideContextMenu(); }
1028
- document.onkeypress = ondockeypress;
1029
- document.onkeydown = ondockeydown;
1030
- document.onkeyup = ondockeyup;
1031
- //window.addEventListener("focus", ondocfocus, false);
1032
- window.addEventListener("blur", ondocblur, false);
1033
- window.onresize = function () { masterUpdate(512); }
1034
- setTimeout("masterUpdate(512)", 200);
1035
-
1036
- // Connect to the mesh server
1037
- meshserver = MeshServerCreateControl(domainUrl, authCookie);
1038
- meshserver.onStateChanged = onStateChanged;
1039
- meshserver.onMessage = onMessage;
1040
- meshserver.trace = (args.trace == 1);
1041
- meshserver.Start();
1042
-
1043
- // Setup page controls
1044
- Q('sortselect').selectedIndex = sort = getstore("sort", 0);
1045
- Q('sizeselect').selectedIndex = getstore("_viewsize", 1);
1046
- Q('SearchInput').value = getstore("_search", "");
1047
- showRealNames = (getstore("showRealNames", 0) == 1);
1048
- Q('RealNameCheckBox').checked = showRealNames;
1049
- Q('viewselect').value = getstore("_deviceView", 1);
1050
- Q('DeskControl').checked = (getstore('DeskControl', 1) == 1);
1051
- QV('accountChangeEmailAddressSpan', (features & 0x200000) == 0);
1052
-
1053
- // Display the page devices
1054
- masterUpdate(3)
1055
- for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
1056
- Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
1057
-
1058
- // Setup upload drag & drop
1059
- Q('p5filetable').addEventListener("drop", p5fileDragDrop, false);
1060
- Q('p5filetable').addEventListener("dragover", p5fileDragOver, false);
1061
- Q('p5filetable').addEventListener("dragleave", p5fileDragLeave, false);
1062
- //Q('p5fileCatchAllInput').addEventListener("drop", p5fileDragDrop, false);
1063
- //Q('p5fileCatchAllInput').addEventListener("dragover", p5fileDragOver, false);
1064
- //Q('p5fileCatchAllInput').addEventListener("dragleave", p5fileDragLeave, false);
1065
-
1066
- // Setup upload drag & drop
1067
- Q('p13filetable').addEventListener("drop", p13fileDragDrop, false);
1068
- Q('p13filetable').addEventListener("dragover", p13fileDragOver, false);
1069
- Q('p13filetable').addEventListener("dragleave", p13fileDragLeave, false);
1070
-
1071
- // Timeline update interval
1072
- setInterval(updateDeviceTimeline, 120000); // Check every 2 minutes
1073
-
1074
- // Load desktop settings
1075
- var t = localStorage.getItem('desktopsettings');
1076
- if (t != null) { desktopsettings = JSON.parse(t); }
1077
- t = localStorage.getItem('multidesktopsettings');
1078
- if (t != null) { multidesktopsettings = JSON.parse(t); }
1079
- applyDesktopSettings();
1080
-
1081
- // Terminal special keys
1082
- var x = '';
1083
- for (var c = 1; c < 27; c++) x += "<option value='" + c + "'>Ctrl-" + String.fromCharCode(64 + c) + " (" + c + ")</option>";
1084
- QH('specialkeylist', x);
1085
-
1086
- // Setup server stats panels
1087
- setupGeneralServerStats();
1088
- setupServerTimelineStats();
1089
-
1090
- // Setup the user interface in the right mode
1091
- userInterfaceSelectMenu();
1092
-
1093
- // If SSPI or LDAP authentication not used, allow batch account creation.
1094
- QV('p4UserBatchCreate', (features & 0x00080000) == 0);
1095
- }
1096
-
1097
- // Toggle the web page to full screen
1098
- function toggleAspectRatio(toggle) {
1099
- if (toggle === 1) { deskAspectRatio = ((deskAspectRatio + 1) % 3); putstore('deskAspectRatio', deskAspectRatio); }
1100
- deskAdjust();
1101
- }
1102
-
1103
- // If FullScreen, toggle menu to be horisontal or vertical
1104
- function toggleStackMenu(toggle) {
1105
- if (webPageFullScreen == true) {
1106
- if (toggle === 1) {
1107
- webPageStackMenu = !webPageStackMenu;
1108
- putstore('webPageStackMenu', webPageStackMenu);
1109
- }
1110
- if (webPageStackMenu == false) {
1111
- QC('body').remove("menu_stack");
1112
- } else {
1113
- QC('body').add("menu_stack");
1114
- if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
1115
- }
1116
- deskAdjust();
1117
- }
1118
- }
1119
-
1120
- // Toggle user interface menu
1121
- function showUserInterfaceSelectMenu() {
1122
- Q('uiViewButton1').classList.remove('uiSelectorSel');
1123
- Q('uiViewButton2').classList.remove('uiSelectorSel');
1124
- Q('uiViewButton3').classList.remove('uiSelectorSel');
1125
- Q('uiViewButton4').classList.remove('uiSelectorSel');
1126
- try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
1127
- QV('uiMenu', (QS('uiMenu').display == 'none'));
1128
- //Q('uiViewButton1').focus();
1129
- if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
1130
- }
1131
-
1132
- function userInterfaceSelectMenu(s) {
1133
- if (s) { uiMode = s; putstore('uiMode', uiMode); }
1134
- webPageFullScreen = (uiMode < 3);
1135
- webPageStackMenu = (uiMode > 1);
1136
- toggleFullScreen(0);
1137
- toggleStackMenu(0);
1138
- if (webPageStackMenu && (xxcurrentView >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
1139
- }
1140
-
1141
- function toggleNightMode() {
1142
- nightMode = !nightMode;
1143
- if (nightMode) { QC('body').add('night'); } else { QC('body').remove('night'); }
1144
- putstore('_nightMode', nightMode?'1':'0');
1145
- }
1146
-
1147
- // Toggle the web page to full screen
1148
- function toggleFullScreen(toggle) {
1149
- if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
1150
- var hide = 0;
1151
- if (args.hide) { hide = parseInt(args.hide); }
1152
- if (webPageFullScreen == false) {
1153
- QC('body').remove("menu_stack");
1154
- QC('body').remove("fullscreen");
1155
- QC('body').remove("arg_hide");
1156
- if (xxcurrentView >= 10) QC('column_l').add('room4submenu');
1157
- QV('UserDummyMenuSpan', false);
1158
- //QV('page_leftbar', false);
1159
- } else {
1160
- QC('body').add("fullscreen");
1161
- if (hide & 16) QC('body').add("arg_hide"); // This is replacement for QV('page_leftbar', !(hide & 16));
1162
- if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
1163
- QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
1164
- }
1165
- masterUpdate(512);
1166
- QV('body', true);
1167
- }
1168
-
1169
- function getNodeFromId(id) { if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } } return null; }
1170
- function reload() {
1171
- var x = window.location.href;
1172
- if (x.endsWith('/#')) { x = x.substring(0, x.length - 2); }
1173
- window.location.href = x;
1174
- }
1175
-
1176
- function onStateChanged(server, state, prevState, errorCode) {
1177
- if (state == 0) {
1178
- // Control web socket disconnected
1179
- setDialogMode(0); // Close any dialog boxes if present
1180
- go(0); // Go to disconnection panel
1181
-
1182
- // Clean up
1183
- powerTimeline = null;
1184
- powerTimelineReq = null;
1185
- powerTimelineNode = null;
1186
- powerTimelineUpdate = null;
1187
- deleteAllNotifications(); // Close and clear notifications if present
1188
- hideContextMenu(); // Hide the context menu if present
1189
- QV('verifyEmailId2', false);
1190
- QV('logoutControl', false);
1191
- if (errorCode == 'noauth') { QH('p0span', 'Unable to perform authentication'); return; }
1192
- if (prevState == 2) { if (autoReconnect) { setTimeout(serverPoll, 5000); } } else { QH('p0span', 'Unable to connect web socket'); }
1193
- if (authCookieRenewTimer != null) { clearInterval(authCookieRenewTimer); authCookieRenewTimer = null; }
1194
- } else if (state == 2) {
1195
- // Fetch list of meshes, nodes, files
1196
- meshserver.send({ action: 'meshes' });
1197
- meshserver.send({ action: 'nodes', id: '{{currentNode}}' });
1198
- if ('{{currentNode}}' == '') { meshserver.send({ action: 'files' }); }
1199
- go(1);
1200
- authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
1201
- }
1202
- }
1203
-
1204
- // Poll the server, if it responds, refresh the page.
1205
- function serverPoll() {
1206
- var xdr = null;
1207
- try { xdr = new XDomainRequest(); } catch (e) { }
1208
- if (!xdr) xdr = new XMLHttpRequest();
1209
- xdr.open("HEAD", window.location.href);
1210
- xdr.timeout = 15000;
1211
- xdr.onload = function () { reload(); };
1212
- xdr.onerror = xdr.ontimeout = function () { setTimeout(serverPoll, 10000); };
1213
- xdr.send();
1214
- }
1215
-
1216
- // Return true if this browser supports clickonce
1217
- function detectClickOnce() {
1218
- for (var i in window.navigator.mimeTypes) { if (window.navigator.mimeTypes[i].type == "application/x-ms-application") { return true; } }
1219
- var userAgent = window.navigator.userAgent.toUpperCase();
1220
- return (userAgent.indexOf('.NET CLR 3.5') >= 0) || (userAgent.indexOf('(WINDOWS NT ') >= 0);
1221
- }
1222
-
1223
- function updateSiteAdmin() {
1224
- var noServerBackup = "{{{noServerBackup}}}";
1225
- var siteRights = userinfo.siteadmin;
1226
- if (noServerBackup == 1) { siteRights &= 0xFFFFFFFA; } // If not server backups allowed, remove server backup and restore permissions
1227
-
1228
- // Update account actions
1229
- QV('p2AccountSecurity', ((features & 4) == 0) && (serverinfo.domainauth == false) && ((features & 4096) != 0)); // Hide Account Security if in single user mode, domain authentication to 2 factor auth not supported.
1230
- QV('p2AccountActions', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide Account Actions if in single user mode or domain authentication
1231
- QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel
1232
- QV('p2ServerActions', siteRights & 21);
1233
- QV('LeftMenuMyServer', siteRights & 21); // 16 + 4 + 1
1234
- QV('MainMenuMyServer', siteRights & 21);
1235
- QV('p2ServerActionsBackup', siteRights & 1);
1236
- QV('p2ServerActionsRestore', siteRights & 4);
1237
- QV('p2ServerActionsVersion', siteRights & 16);
1238
- QV('MainMenuMyFiles', siteRights & 8);
1239
- QV('LeftMenuMyFiles', siteRights & 8);
1240
- if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { setDialogMode(0); go(1); }
1241
- if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
1242
-
1243
- // Update user management state
1244
- if ((userinfo.siteadmin & 2) != 0)
1245
- {
1246
- // We are user administrator
1247
- if (users == null) { meshserver.send({ action: 'users' }); }
1248
- if (wssessions == null) { meshserver.send({ action: 'wssessioncount' }); }
1249
- } else {
1250
- // We are not user administrator
1251
- users = null;
1252
- wssessions = null;
1253
- updateUsers();
1254
- if (xxcurrentView == 4 || ((xxcurrentView >= 30) && (xxcurrentView < 40))) { setDialogMode(0); go(1); currentUser = null; }
1255
- }
1256
- meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
1257
- QV('p2deleteall', userinfo.siteadmin == 0xFFFFFFFF);
1258
- QV('ServerConsole', userinfo.siteadmin === 0xFFFFFFFF);
1259
- if ((xxcurrentView == 115) && (userinfo.siteadmin != 0xFFFFFFFF)) { go(6); }
1260
- if ((xxcurrentView == 6) && ((userinfo.siteadmin & 21) == 0)) { go(1); }
1261
-
1262
- // If we are site administrator, register to get server statistics
1263
- if ((siteRights & 21) != 0) { meshserver.send({ action: 'serverstats', interval: 10000 }); }
1264
- }
1265
-
1266
- // To boost the speed of the web page when even floods occur, this method perform a delayed update on the web page.
1267
- var updateNaggleTimer = null;
1268
- var updateNaggleFlags = 0;
1269
- function masterUpdate(flags) {
1270
- updateNaggleFlags |= flags;
1271
- if (updateNaggleTimer == null) {
1272
- updateNaggleTimer = setTimeout(function () {
1273
- if (updateNaggleFlags & 512) { center(); }
1274
- if (updateNaggleFlags & 1) { onSearchInputChanged(); }
1275
- if (updateNaggleFlags & 2) { onSortSelectChange(false); }
1276
- if (updateNaggleFlags & 128) { updateMeshes(); }
1277
- if (updateNaggleFlags & 4) { updateDevices(); }
1278
- if (updateNaggleFlags & 8) { drawNotifications(); }
1279
- if (updateNaggleFlags & 16) { updateMapMarkers(); }
1280
- if (updateNaggleFlags & 32) { eventsUpdate(); }
1281
- if (updateNaggleFlags & 64) { refreshMap(false, true); }
1282
- if (updateNaggleFlags & 256) { drawDeviceTimeline(); }
1283
- if (updateNaggleFlags & 1024) { deviceEventsUpdate(); }
1284
- if (updateNaggleFlags & 2048) { userEventsUpdate(); }
1285
- if (updateNaggleFlags & 4096) { p20updateMesh(); }
1286
- updateNaggleTimer = null;
1287
- updateNaggleFlags = 0;
1288
- }, 150);
1289
- }
1290
- }
1291
-
1292
- function updateSelf() {
1293
- QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
1294
- QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
1295
- QV('manageOtp', (userinfo.otpsecret == 1) || (userinfo.otphkeys > 0));
1296
- QV('authAppSetupCheck', userinfo.otpsecret == 1);
1297
- QV('authKeySetupCheck', userinfo.otphkeys > 0);
1298
- QV('authCodesSetupCheck', userinfo.otpkeys > 0);
1299
- masterUpdate(4 + 128 + 4096);
1300
-
1301
- // If we can't create new groups, hide all links that can do that.
1302
- var newGroupsAllowed = ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 64) == 0));
1303
- QV('p2createMeshLink1', newGroupsAllowed);
1304
- QV('p2createMeshLink2', newGroupsAllowed);
1305
- QV('getStarted1', newGroupsAllowed);
1306
- QV('getStarted2', !newGroupsAllowed);
1307
-
1308
- if (typeof userinfo.passchange == 'number') {
1309
- if (userinfo.passchange == -1) { QH('p2nextPasswordUpdateTime', ' - Reset on next login.'); }
1310
- else if ((passRequirements != null) && (typeof passRequirements.reset == 'number')) {
1311
- var seconds = (userinfo.passchange) + (passRequirements.reset * 86400) - Math.floor(Date.now() / 1000);
1312
- if (seconds < 0) { QH('p2nextPasswordUpdateTime', ' - Reset on next login.'); }
1313
- else if (seconds < 3600) { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 60) + ' minute' + addLetterS(Math.floor(seconds / 60)) + '.'); }
1314
- else if (seconds < 86400) { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 3600) + ' hour' + addLetterS(Math.floor(seconds / 3600)) + '.'); }
1315
- else { QH('p2nextPasswordUpdateTime', ' - Reset in ' + Math.floor(seconds / 86400) + ' day' + addLetterS(Math.floor(seconds / 86400)) + '.'); }
1316
- }
1317
- }
1318
- }
1319
-
1320
- function addLetterS(x) { return (x > 1) ? 's' : ''; }
1321
- function setSessionActivity() { sessionActivity = Date.now(); QH('idleTimeoutNotify', ''); }
1322
- function checkIdleSessionTimeout() {
1323
- var delta = (Date.now() - sessionActivity);
1324
- if (delta > serverinfo.timeout) { window.location.href = 'logout'; } else {
1325
- var ds = Math.round((serverinfo.timeout - delta) / 1000);
1326
- if (ds <= 60) {
1327
- QH('idleTimeoutNotify', '<br />' + ds + ' second' + addLetterS(ds) + ' until disconnect');
1328
- } else {
1329
- ds = Math.round(ds / 60);
1330
- if (ds <= 5) { QH('idleTimeoutNotify', '<br />' + ds + ' minute' + addLetterS(ds) + ' until disconnect'); }
1331
- }
1332
- }
1333
- }
1334
-
1335
- function onMessage(server, message) {
1336
- switch (message.action) {
1337
- case 'serverstats': {
1338
- updateGeneralServerStats(message);
1339
- break;
1340
- }
1341
- case 'servertimelinestats': {
1342
- setServerTimelineStats(message.events);
1343
- break;
1344
- }
1345
- case 'authcookie': {
1346
- // Got an authentication cookie refresh
1347
- authCookie = message.cookie;
1348
- break;
1349
- }
1350
- case 'serverinfo': {
1351
- serverinfo = message.serverinfo;
1352
- if (serverinfo.timeout) { setInterval(checkIdleSessionTimeout, 10000); checkIdleSessionTimeout(); }
1353
- break;
1354
- }
1355
- case 'userinfo': {
1356
- userinfo = message.userinfo;
1357
- updateSiteAdmin();
1358
- updateSelf();
1359
- break;
1360
- }
1361
- case 'users': {
1362
- users = {};
1363
- for (var m in message.users) { users[message.users[m]._id] = message.users[m]; }
1364
- updateUsers();
1365
- break;
1366
- }
1367
- case 'wssessioncount': {
1368
- wssessions = message.wssessions;
1369
- updateUsers();
1370
- break;
1371
- }
1372
- case 'meshes': {
1373
- meshes = {};
1374
- for (var m in message.meshes) { meshes[message.meshes[m]._id] = message.meshes[m]; }
1375
- masterUpdate(4 + 128);
1376
- break;
1377
- }
1378
- case 'files': {
1379
- filetree = setupBackPointers(message.filetree);
1380
- updateFiles();
1381
- d3updatefiles();
1382
- break;
1383
- }
1384
- case 'nodes': {
1385
- nodes = [];
1386
- for (var m in message.nodes) {
1387
- if (!meshes[m]) { console.log('Invalid mesh (1): ' + m); continue; }
1388
- for (var n in message.nodes[m]) {
1389
- if (message.nodes[m][n]._id == null) { console.log('Invalid node (' + n + '): ' + JSON.stringify(message.nodes)); continue; }
1390
- message.nodes[m][n].namel = message.nodes[m][n].name.toLowerCase();
1391
- if (message.nodes[m][n].rname) { message.nodes[m][n].rnamel = message.nodes[m][n].rname.toLowerCase(); } else { message.nodes[m][n].rnamel = message.nodes[m][n].namel; }
1392
- message.nodes[m][n].meshnamel = meshes[m].name.toLowerCase();
1393
- message.nodes[m][n].meshid = m;
1394
- message.nodes[m][n].state = (message.nodes[m][n].state)?(message.nodes[m][n].state):0;
1395
- message.nodes[m][n].desc = message.nodes[m][n].desc;
1396
- message.nodes[m][n].ip = message.nodes[m][n].ip;
1397
- if (!message.nodes[m][n].icon) message.nodes[m][n].icon = 1;
1398
- message.nodes[m][n].ident = ++nodeShortIdent;
1399
- nodes.push(message.nodes[m][n]);
1400
- }
1401
- }
1402
- masterUpdate(1 | 2 | 4 | 64);
1403
-
1404
- if (xxcurrentView == 0) { if ('{{viewmode}}' != '') { go(parseInt('{{viewmode}}')); } else { setDialogMode(0); go(1); } }
1405
- if ('{{currentNode}}' != '') { gotoDevice('{{currentNode}}',parseInt('{{viewmode}}'));}
1406
- break;
1407
- }
1408
- case 'powertimeline': {
1409
- if (message.nodeid != powerTimelineReq) break;
1410
- powerTimelineNode = message.nodeid;
1411
- powerTimeline = message.timeline;
1412
- powerTimelineUpdate = Date.now() + 300000; // Update every 5 minutes
1413
- for (var i in powerTimeline) { if (i % 2 == 1) { powerTimeline[i] = powerTimeline[i] * 1000; } } // Decompress time
1414
- if (currentNode._id == message.nodeid) { masterUpdate(256); }
1415
- break;
1416
- }
1417
- case 'lastconnect': {
1418
- var node = getNodeFromId(message.nodeid);
1419
- if (node != null) {
1420
- node.lastconnect = message.time;
1421
- node.lastaddr = message.addr;
1422
- if ((currentNode._id == node._id) && (Q('MainComputerState').innerHTML == '')) {
1423
- QH('MainComputerState', '<span>Last seen:<br />' + printDateTime(new Date(node.lastconnect)) + '</span>');
1424
- }
1425
- }
1426
- break;
1427
- }
1428
- case 'msg': {
1429
- // Check if this is a message from a node
1430
- if (message.nodeid != null) {
1431
- var index = -1;
1432
- if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == message.nodeid) { index = i; break; } } }
1433
- if (index != -1) {
1434
- // Node was found, dispatch the message
1435
- if (message.type == 'console') { p15consoleReceive(nodes[index], message.value); } // This is a console message.
1436
- else if (message.type == 'notify') { // This is a notification message.
1437
- var n = getstore('notifications', 0);
1438
- if (((n & 8) == 0) && (message.amtMessage != null)) { break; } // Intel AMT desktop & terminal messages should be ignored.
1439
- var n = { text: message.value, title: message.title, icon: message.icon };
1440
- if (message.nodeid != null) { n.nodeid = message.nodeid; }
1441
- if (message.tag != null) { n.tag = message.tag; }
1442
- if (message.username != null) { n.username = message.username; }
1443
- addNotification(n);
1444
- } else if (message.type == 'ps') {
1445
- showDeskToolsProcesses(message);
1446
- } else if ((message.type == 'getclip') && (xxdialogTag == 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
1447
- Q('d2clipText').value = message.data;
1448
- } else if ((message.type == 'setclip') && (xxdialogTag == 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
1449
- // Display success/fail on the clipboard dialog box.
1450
- QH('dlgClipStatus', message.success ? '<span style=color:green>Success</span>' : '<span style=color:red>Failed</span>')
1451
- setTimeout(function () { try { QH('dlgClipStatus', ''); } catch (ex) { } }, 2000);
1452
- }
1453
- }
1454
- } else {
1455
- if (message.type == 'notify') { // This is a notification message.
1456
- var n = { text: message.value, title: message.title, icon: message.icon };
1457
- if (message.tag != null) { n.tag = message.tag; }
1458
- if (message.username != null) { n.username = message.username; }
1459
- addNotification(n);
1460
- }
1461
- }
1462
- break;
1463
- }
1464
- case 'getnetworkinfo': {
1465
- if ((currentNode._id == message.nodeid) && (xxdialogMode == 2) && (xxdialogTag == 'if' + message.nodeid)) {
1466
- if (message.netif == null) {
1467
- QH('d2netinfo', 'No network interface information available for this device.');
1468
- } else {
1469
- var x = '<div class=dialogText>';
1470
-
1471
- if (currentNode.lastconnect) { x += addHtmlValue2('Last agent connection', printDateTime(new Date(currentNode.lastconnect))); }
1472
- if (currentNode.lastaddr) {
1473
- var splitip = currentNode.lastaddr.split(':');
1474
- if (splitip.length > 2) {
1475
- // IPv6
1476
- x += addHtmlValue2('Last agent address', currentNode.lastaddr);
1477
- } else {
1478
- // IPv4
1479
- if (isPrivateIP(currentNode.lastaddr)) {
1480
- x += addHtmlValue2('Last agent address', splitip[0]);
1481
- } else {
1482
- x += addHtmlValue2('Last agent address', '<a href="https://iplocation.com/?ip=' + splitip[0] + '" rel="noreferrer noopener" target="MeshIPLoopup">' + splitip[0] + '</a>');
1483
- }
1484
- }
1485
- }
1486
-
1487
- x += addHtmlValue2('Last interfaces update', printDateTime(new Date(message.updateTime)));
1488
- for (var i in message.netif) {
1489
- var net = message.netif[i];
1490
- x += '<hr />'
1491
- if (net.name) { x += addHtmlValue2('Name', '<b>' + EscapeHtml(net.name) + '</b>'); }
1492
- if (net.desc) { x += addHtmlValue2('Description', EscapeHtml(net.desc).replace('(R)', '®').replace('(r)', '®')); }
1493
- if (net.dnssuffix) { x += addHtmlValue2('DNS suffix', EscapeHtml(net.dnssuffix)); }
1494
- if (net.mac) { x += addHtmlValue2('MAC address', '<a href="https://dnslytics.com/mac-address-lookup/' + net.mac.substring(0,6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.mac.toLowerCase()) + '</a>'); }
1495
- if (net.v4addr) { x += addHtmlValue2('IPv4 address', EscapeHtml(net.v4addr)); }
1496
- if (net.v4mask) { x += addHtmlValue2('IPv4 mask', EscapeHtml(net.v4mask)); }
1497
- if (net.v4gateway) { x += addHtmlValue2('IPv4 gateway', EscapeHtml(net.v4gateway)); }
1498
- if (net.gatewaymac) { x += addHtmlValue2('Gateway MAC', '<a href="https://dnslytics.com/mac-address-lookup/' + net.gatewaymac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.gatewaymac.toLowerCase()) + '</a>'); }
1499
- }
1500
- x += '</div>';
1501
- QH('d2netinfo', x);
1502
- }
1503
- }
1504
- break;
1505
- }
1506
- case 'serverversion': {
1507
- if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerUpdate')) {
1508
- var x = '<div class=dialogText>';
1509
- if (!message.current) { message.current = 'Unknown'; }
1510
- if (!message.latest) { message.latest = 'Unknown'; }
1511
- x += addHtmlValue2('Current Version', '<b>' + EscapeHtml(message.current) + '</b>');
1512
- x += addHtmlValue2('Latest Version', '<b>' + EscapeHtml(message.latest) + '</b>');
1513
- x += '</div>';
1514
- if ((message.latest.indexOf('.') == -1) || (message.current == message.latest) || ((features & 2048) == 0)) {
1515
- setDialogMode(2, "MeshCentral Version", 1, null, x);
1516
- } else {
1517
- setDialogMode(2, "MeshCentral Version", 3, server_showVersionDlgEx, x + '<br /><label><input id=d2updateCheck type=checkbox onclick=server_showVersionDlgUpdate() /> Check and click OK to start server self-update.</label>');
1518
- server_showVersionDlgUpdate();
1519
- }
1520
- }
1521
- break;
1522
- }
1523
- case 'servererrors': {
1524
- if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerErrors')) {
1525
- if (message.data == null) {
1526
- setDialogMode(2, "MeshCentral Server Errors", 1, null, 'Server has no error log.');
1527
- } else {
1528
- var x = '<div class="dialogText dialogTextLog"><pre id=d2ServerErrorsLogPre>' + message.data + '<pre></div>';
1529
- setDialogMode(2, "MeshCentral Server Errors", 3, server_showErrorsDlgEx, x + '<br /><div style=float:right><img src=images/link4.png height=10 width=10 title="Download error log" style=cursor:pointer onclick=d2CopyServerErrorsToClip()></div><div><label><input id=d2updateCheck type=checkbox onclick=server_showVersionDlgUpdate() /> Check and click OK to clear error log.</label></div>');
1530
- server_showVersionDlgUpdate();
1531
- }
1532
- }
1533
- break;
1534
- }
1535
- case 'serverconsole': {
1536
- p15consoleReceive('serverconsole', message.value);
1537
- break;
1538
- }
1539
- case 'events': {
1540
- if ((message.nodeid != null) && (message.nodeid == currentNode._id)) {
1541
- currentDeviceEvents = message.events;
1542
- masterUpdate(1024);
1543
- } else if ((message.user != null) && (message.user == currentUser.name)) {
1544
- currentUserEvents = message.events;
1545
- masterUpdate(2048);
1546
- } else {
1547
- events = message.events;
1548
- masterUpdate(32);
1549
- }
1550
- break;
1551
- }
1552
- case 'getcookie': {
1553
- if (message.tag == 'clickonce') {
1554
- var basicPort = "{{{serverRedirPort}}}" == "" ? "{{{serverPublicPort}}}" : "{{{serverRedirPort}}}";
1555
- var rdpurl = "http://" + window.location.hostname + ":" + basicPort + "/clickonce/minirouter/MeshMiniRouter.application?WS=wss%3A%2F%2F" + window.location.hostname + "%2Fmeshrelay.ashx%3Fauth=" + message.cookie + "&CH={{{webcerthash}}}&AP=" + message.protocol + ((debugmode == 1) ? "" : "&HOL=1");
1556
- var newWindow = window.open(rdpurl, '_blank');
1557
- newWindow.opener = null;
1558
- }
1559
- break;
1560
- }
1561
- case 'getNotes': {
1562
- var n = Q('d2devNotes');
1563
- if (n && (message.id == decodeURIComponent(n.attributes['noteid'].value))) {
1564
- if (message.notes) { QH('d2devNotes', decodeURIComponent(message.notes)); } else { QH('d2devNotes', ''); }
1565
- var ro = (n.attributes['ro'].value == 'true');
1566
- if (ro == false) { // If we have permissions, set read/write on this note.
1567
- n.removeAttribute('readonly');
1568
- QE('idx_dlgOkButton', true);
1569
- QV('idx_dlgOkButton', true);
1570
- focusTextBox('d2devNotes');
1571
- }
1572
- }
1573
- break;
1574
- }
1575
- case 'otpauth-request': {
1576
- if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-request')) {
1577
- var secret = message.secret;
1578
- if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); }
1579
- else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '<br/>' + secret.substring(20) }
1580
- QH('d2optinfo', '<table style=width:380px><tr><td style=vertical-align:top>Install <a href=\"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2\" rel=\"noreferrer noopener\" target=_blank>Google Authenticator</a> or a compatible application and scan the barcode, use <a href=\"' + message.url + '\" rel=\"noreferrer noopener\" target=_blank> this link</a> or enter the secret. Then, enter the current 6 digit token below to activate 2-Step login.<br /><br />Secret<br /><tt id=d2optsecret secret=\"' + message.secret + '\" style=font-size:12px>' + secret + '</tt><br /><br /></td><td style=width:1px;vertical-align:top><a href=\"' + message.url + '\" rel=\"noreferrer noopener\" target=_blank><div id="qrcode"></div></a></td><tr><td colspan=2 style="text-align:center;border-top:1px solid black"><br />Enter the token here for 2-step login: <input type=text onkeypress=\"return (event.keyCode == 8) || (event.charCode >= 48 && event.charCode <= 57)\" onkeyup=account_addOtpCheck(event) onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type=text></td></table>');
1581
- new QRCode(Q("qrcode"), { text: message.url, width: 128, height: 128, colorDark: "#000000", colorLight: "#EEE", correctLevel: QRCode.CorrectLevel.H });
1582
- QV('idx_dlgOkButton', true);
1583
- QE('idx_dlgOkButton', false);
1584
- Q('d2otpauthinput').focus();
1585
- }
1586
- break;
1587
- }
1588
- case 'otpauth-setup': {
1589
- if (xxdialogMode) return;
1590
- setDialogMode(2, "Authenticator App", 1, null, message.success ? "<b style=color:green>Authenticator app activation successful</b>. You will now need a valid token to login again." : "<b style=color:red>2-step login activation failed</b>. Clear the secret from the application and try again. You only have a few minutes to enter the proper code.");
1591
- break;
1592
- }
1593
- case 'otpauth-clear': {
1594
- if (xxdialogMode) return;
1595
- setDialogMode(2, "Authenticator App", 1, null, message.success ? "<b>Authenticator application removed</b>. You can reactivate this feature at any time." : "<b style=color:red>2-step login activation removal failed</b>. Try again.");
1596
- break;
1597
- }
1598
- case 'otpauth-getpasswords': {
1599
- if (xxdialogMode) return;
1600
- var x = "One time tokens can be used as secondary authentication. Generate a set, print them and keep them in a safe place.";
1601
- x += "<div style='border-radius:6px;border: 2px dashed #888;width:100%;margin-top:8px'><div style='padding:8px;font-family:Arial, Helvetica, sans-serif;font-size:20px;font-weight:bold'><table style=width:100%;text-align:center>";
1602
- if (message.passwords) {
1603
- var j = 0;
1604
- for (var i in message.passwords) {
1605
- if (++j % 2) { x += '<tr>'; }
1606
- var p = '' + message.passwords[i].p;
1607
- while (p.length < 8) { p = '0' + p; }
1608
- if (message.passwords[i].u === true) { x += '<td>' + p.substring(0, 4) + ' ' + p.substring(4); } else { x += '<td><strike style=color:#BBB>' + p.substring(0, 4) + ' ' + p.substring(4); + '</strike>'; }
1609
- }
1610
- } else {
1611
- x += '<tr><td>No Active Tokens';
1612
- }
1613
- x += "</table></div></div><br />";
1614
- x += "<div><input type=button value='Close' onclick=setDialogMode(0) style=float:right></input>";
1615
- x += "<input type=button value='Generate New Tokens' onclick='account_manageOtp(1);'></input>";
1616
- if (message.passwords != null) { x += "<input type=button value='Clear Tokens' onclick='account_manageOtp(2);'></input>"; }
1617
- x += "</div><br />";
1618
- setDialogMode(2, "Manage Backup Codes", 8, null, x, 'otpauth-manage');
1619
- break;
1620
- }
1621
- case 'otp-hkey-get': {
1622
- if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
1623
- var start = "<div style='border-radius:6px;border:2px solid #CCC;background-color:#BBB;width:100%;box-sizing:border-box;margin-bottom:6px'><div style='margin:3px;font-family:Arial, Helvetica, sans-serif;font-size:16px;font-weight:bold'><table style=width:100%;text-align:left>";
1624
- var end = "</table></div></div>";
1625
- var x = "<a href='https://www.yubico.com/' rel='noreferrer noopener' target='_blank'>Hardware keys</a> are used as secondary login authentication.";
1626
- x += "<div style='max-height:150px;overflow-y:auto;overflow-x:hidden;margin-top:6px;margin-bottom:6px'>";
1627
- if (message.keys && message.keys.length > 0) {
1628
- for (var i in message.keys) {
1629
- var key = message.keys[i], type = (key.type == 2)?'OTP':'WebAuthn';
1630
- x += start + '<tr style=margin:5px><td style=width:30px><img width=24 height=18 src="images/hardware-key-' + type + '-24.png" style=margin-top:4px><td style=width:250px>' + key.name + "<td><input type=button value='Remove' onclick=account_removehkey(" + key.i + ")></input>" + end;
1631
- }
1632
- } else {
1633
- x += start + '<tr style=text-align:center><td>No Keys Configured' + end;
1634
- }
1635
- x += "</div>";
1636
- x += "<div><input type=button value='Close' onclick=setDialogMode(0) style=float:right></input>";
1637
- if ((features & 0x00020000) != 0) { x += "<input id=d2addkey3 type=button value='Add Key' onclick='account_addhkey(3);'></input>"; }
1638
- if ((features & 0x00004000) != 0) { x += "<input id=d2addkey2 type=button value='Add YubiKey® OTP' onclick='account_addhkey(2);'></input>"; }
1639
- x += "</div><br />";
1640
- setDialogMode(2, "Manage Security Keys", 8, null, x, 'otpauth-hardware-manage');
1641
- if (u2fSupported() == false) { QE('d2addkey1', false); }
1642
- break;
1643
- }
1644
- case 'otp-hkey-yubikey-add': {
1645
- if (message.result) {
1646
- meshserver.send({ action: 'otp-hkey-get' }); // Success, ask for the full list of keys.
1647
- } else {
1648
- setDialogMode(2, "Add Security Key", 1, null, '<br />Error, Unable to add key.<br /><br />');
1649
- }
1650
- break;
1651
- }
1652
- case 'otp-hkey-setup-response': {
1653
- if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
1654
- if (message.result == true) {
1655
- meshserver.send({ action: 'otp-hkey-get' }); // Success, ask for the full list of keys.
1656
- } else {
1657
- setDialogMode(2, "Add Security Key", 1, null, '<br />ERROR: Unable to add key.<br /><br />', 'otpauth-hardware-manage');
1658
- }
1659
- break;
1660
- }
1661
- case 'webauthn-startregister': {
1662
- if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
1663
- var x = "Press the key button now.<br /><br /><div style=width:100%;text-align:center><img width=120 height=117 src='images/hardware-keypress-120.png' /></div><input id=dp1keyname style=display:none value=" + message.name + " />";
1664
- setDialogMode(2, "Add Security Key", 2, null, x);
1665
-
1666
- var publicKey = message.request;
1667
- message.request.challenge = Uint8Array.from(atob(message.request.challenge), function (c) { return c.charCodeAt(0) })
1668
- message.request.user.id = Uint8Array.from(atob(message.request.user.id), function (c) { return c.charCodeAt(0) })
1669
- navigator.credentials.create({ publicKey: publicKey })
1670
- .then(function(newCredentialInfo) {
1671
- // Public key credential
1672
- var r = { rawId: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.rawId))), response: { attestationObject: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.response.attestationObject))), clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.response.clientDataJSON))) }, type: newCredentialInfo.type };
1673
- meshserver.send({ action: 'webauthn-endregister', response: r });
1674
- setDialogMode(0);
1675
- }, function(error) {
1676
- // Error
1677
- setDialogMode(2, "Add Security Key", 1, null, "ERROR: " + error);
1678
- });
1679
- break;
1680
- }
1681
- case 'event': {
1682
- if (!message.event.nolog) {
1683
- events.unshift(message.event);
1684
- var eventLimit = parseInt(p3limitdropdown.value);
1685
- while (events.length > eventLimit) { events.pop(); } // Remove element(s) at the end
1686
- masterUpdate(32);
1687
- }
1688
- if (message.event.noact) break; // Take no action on this event
1689
- switch (message.event.action) {
1690
- case 'userWebState': {
1691
- // New user web state, update the web page as needed
1692
- if (localStorage != null) {
1693
- var oldShowRealNames = localStorage.getItem('showRealNames');
1694
- var oldUiMode = localStorage.getItem('uiMode');
1695
- var oldSort = localStorage.getItem('sort');
1696
-
1697
- var webstate = JSON.parse(message.event.state);
1698
- for (var i in webstate) { localStorage.setItem(i, webstate[i]); }
1699
-
1700
- // Update the web page
1701
- if ((webstate.deskAspectRatio != null) && (webstate.deskAspectRatio != deskAspectRatio)) { deskAspectRatio = webstate.deskAspectRatio; deskAdjust(); }
1702
- if ((webstate.showRealNames != null) && (webstate.showRealNames != oldShowRealNames)) { showRealNames = Q('RealNameCheckBox').checked = (webstate.showRealNames == "1"); masterUpdate(6); }
1703
- if ((webstate.uiMode != null) && (webstate.uiMode != oldUiMode)) { userInterfaceSelectMenu(parseInt(webstate.uiMode)); }
1704
- if ((webstate.sort != null) && (webstate.sort != oldSort)) { document.getElementById("sortselect").selectedIndex = sort = parseInt(webstate.sort); masterUpdate(6); }
1705
- }
1706
- break;
1707
- }
1708
- case 'servertimelinestats': { addServerTimelineStats(message.event.data); break; }
1709
- case 'accountcreate':
1710
- case 'accountchange': {
1711
- // An account was created or changed
1712
- if (userinfo.name == message.event.account.name) {
1713
- var newsiteadmin = message.event.account.siteadmin?message.event.account.siteadmin:0;
1714
- var oldsiteadmin = userinfo.siteadmin?userinfo.siteadmin:0;
1715
- if ((message.event.account.quota != userinfo.quota) || (((userinfo.siteadmin & 8) == 0) && ((message.event.account.siteadmin & 8) != 0))) { meshserver.send({ action: 'files' }); }
1716
- var oldgroups = userinfo.groups;
1717
- userinfo = message.event.account;
1718
- if (oldsiteadmin != newsiteadmin) updateSiteAdmin();
1719
- updateSelf();
1720
-
1721
- if ((userinfo.siteadmin & 2) != 0) {
1722
- // Compare our groups
1723
- var og = oldgroups ? oldgroups : [];
1724
- var ng = userinfo.groups ? userinfo.groups : [];
1725
- if (og.join(',') != ng.join(',')) {
1726
- // Our groups have changed, re-ask for a list of users.
1727
- users = wssessions = null;
1728
- meshserver.send({ action: 'users' });
1729
- meshserver.send({ action: 'wssessioncount' });
1730
- }
1731
- }
1732
- }
1733
- if (users == null) break;
1734
-
1735
- // Check if the account is part of our user group
1736
- if ((userinfo.groups == null) || (userinfo.groups.length == 0) || (findOne(message.event.account.groups, userinfo.groups) == true)) {
1737
- users[message.event.account._id] = message.event.account; // Part of our groups, update this user.
1738
- } else {
1739
- delete users[message.event.account._id]; // No longer part of our groups, remove this user.
1740
- }
1741
-
1742
- updateUsers();
1743
- break;
1744
- }
1745
- case 'accountremove': {
1746
- // An account was removed
1747
- if (users == null) break;
1748
- delete users['user/' + domain + '/' + message.event.username.toLowerCase()];
1749
- updateUsers();
1750
- break;
1751
- }
1752
- case 'createmesh': {
1753
- // A new mesh was created
1754
- if ((meshes[message.event.meshid] == null) && (message.event.links[userinfo._id] != null)) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
1755
- meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
1756
- masterUpdate(4 + 128);
1757
- meshserver.send({ action: 'files' });
1758
- }
1759
- break;
1760
- }
1761
- case 'meshchange': {
1762
- // Update mesh information
1763
- if (meshes[message.event.meshid] == null) {
1764
- // This is a new mesh for us
1765
- meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
1766
- meshserver.send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh).
1767
- } else {
1768
- // This is an existing mesh
1769
- if (message.event.name != null) { meshes[message.event.meshid].name = message.event.name; }
1770
- if (message.event.desc != null) { meshes[message.event.meshid].desc = message.event.desc; }
1771
- if (message.event.flags != null) { meshes[message.event.meshid].flags = message.event.flags; }
1772
- if (message.event.consent != null) { meshes[message.event.meshid].consent = message.event.consent; }
1773
- if (message.event.links) { meshes[message.event.meshid].links = message.event.links; }
1774
- if (message.event.amt) { meshes[message.event.meshid].amt = message.event.amt; }
1775
-
1776
- // Check if we lost rights to this mesh in this change.
1777
- if (meshes[message.event.meshid].links[userinfo._id] == null) {
1778
- if ((xxcurrentView == 20) && (currentMesh == meshes[message.event.meshid])) go(2);
1779
- delete meshes[message.event.meshid];
1780
-
1781
- // Delete all nodes in that mesh
1782
- var newnodes = [];
1783
- for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } }
1784
- nodes = newnodes;
1785
-
1786
- // If we are looking at a node in the deleted mesh, move back to "My Devices"
1787
- if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); }
1788
- }
1789
- }
1790
- masterUpdate(4 + 128);
1791
- if (currentNode && (currentNode.meshid == message.event.meshid)) { currentNode = null; if ((xxcurrentView >= 10) && (xxcurrentView < 20)) { go(1); } }
1792
- //meshserver.send({ action: 'files' }); // TODO: Why do we need to do this??
1793
-
1794
- // If we are looking at a mesh that is now deleted, move back to "My Account"
1795
- if (xxcurrentView == 20 && currentMesh._id == message.event.meshid) { masterUpdate(4096); }
1796
- break;
1797
- }
1798
- case 'deletemesh': {
1799
- // Delete the mesh
1800
- if (meshes[message.event.meshid]) {
1801
- delete meshes[message.event.meshid];
1802
- masterUpdate(128);
1803
- meshserver.send({ action: 'files' });
1804
- }
1805
-
1806
- // Delete all nodes in that mesh
1807
- var newnodes = [];
1808
- if (nodes != null) { for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } } }
1809
- nodes = newnodes;
1810
- masterUpdate(4);
1811
-
1812
- // If we are looking at a mesh that is now deleted, move back to "My Account"
1813
- if (xxcurrentView >= 20 && xxcurrentView < 30 && currentMesh._id == message.event.meshid) { setDialogMode(0); go(2); }
1814
- // If we are looking at a node in the deleted mesh, move back to "My Devices"
1815
- if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); }
1816
-
1817
- break;
1818
- }
1819
- case 'addnode': {
1820
- var node = message.event.node;
1821
- if (!meshes[node.meshid]) break; // This is a node for a mesh we don't know. Happens when we are site administrator, we get all messages.
1822
- if (getNodeFromId(node._id) != null) break; // This node is already known.
1823
- node.namel = node.name.toLowerCase();
1824
- if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
1825
- node.meshnamel = meshes[node.meshid].name.toLowerCase();
1826
- node.state = 0;
1827
- if (!node.icon) node.icon = 1;
1828
- node.ident = ++nodeShortIdent;
1829
- if (nodes == null) { }
1830
- nodes.push(node);
1831
-
1832
- // Web page update
1833
- masterUpdate(1 | 2 | 4 | 16);
1834
-
1835
- break;
1836
- }
1837
- case 'removenode': {
1838
- var index = -1;
1839
- for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
1840
- if (index != -1) {
1841
- var node = nodes[index];
1842
- if (currentNode == node) {
1843
- if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); }
1844
- currentNode = null;
1845
- // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
1846
- }
1847
- nodes.splice(index, 1);
1848
-
1849
- // Web page update
1850
- masterUpdate(4 | 16);
1851
- }
1852
- break;
1853
- }
1854
- case 'changenode': {
1855
- var index = -1;
1856
- for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
1857
- if (index != -1) {
1858
- var node = nodes[index];
1859
-
1860
- // Change the node
1861
- node.name = message.event.node.name;
1862
- node.rname = message.event.node.rname;
1863
- node.users = message.event.node.users;
1864
- node.host = message.event.node.host;
1865
- node.desc = message.event.node.desc;
1866
- node.ip = message.event.node.ip;
1867
- node.osdesc = message.event.node.osdesc;
1868
- node.publicip = message.event.node.publicip;
1869
- node.iploc = message.event.node.iploc;
1870
- node.wifiloc = message.event.node.wifiloc;
1871
- node.gpsloc = message.event.node.gpsloc;
1872
- node.tags = message.event.node.tags;
1873
- node.userloc = message.event.node.userloc;
1874
- if (message.event.node.agent != null) {
1875
- if (node.agent == null) node.agent = {};
1876
- if (message.event.node.agent.ver != null) { node.agent.ver = message.event.node.agent.ver; }
1877
- if (message.event.node.agent.id != null) { node.agent.id = message.event.node.agent.id; }
1878
- if (message.event.node.agent.caps != null) { node.agent.caps = message.event.node.agent.caps; }
1879
- if (message.event.node.agent.core != null) { node.agent.core = message.event.node.agent.core; } else { if (node.agent.core) { delete node.agent.core; } }
1880
- node.agent.tag = message.event.node.agent.tag;
1881
- }
1882
- if (message.event.node.intelamt != null) {
1883
- if (node.intelamt == null) node.intelamt = {};
1884
- if (message.event.node.intelamt.state != null) { node.intelamt.state = message.event.node.intelamt.state; }
1885
- if (message.event.node.intelamt.host != null) { node.intelamt.user = message.event.node.intelamt.host; }
1886
- if (message.event.node.intelamt.user != null) { node.intelamt.user = message.event.node.intelamt.user; }
1887
- if (message.event.node.intelamt.tls != null) { node.intelamt.tls = message.event.node.intelamt.tls; }
1888
- if (message.event.node.intelamt.ver != null) { node.intelamt.ver = message.event.node.intelamt.ver; }
1889
- if (message.event.node.intelamt.tag != null) { node.intelamt.tag = message.event.node.intelamt.tag; }
1890
- if (message.event.node.intelamt.uuid != null) { node.intelamt.uuid = message.event.node.intelamt.uuid; }
1891
- if (message.event.node.intelamt.realm != null) { node.intelamt.realm = message.event.node.intelamt.realm; }
1892
- }
1893
- node.namel = node.name.toLowerCase();
1894
- if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
1895
- if (message.event.node.icon) { node.icon = message.event.node.icon; }
1896
-
1897
- // Web page update
1898
- masterUpdate(2 | 4 | 8 | 16);
1899
- refreshDevice(node._id);
1900
-
1901
- if ((currentNode == node) && (xxdialogMode != null) && (xxdialogTag == '@xxmap')) { p10showNodeLocationDialog(); }
1902
- }
1903
- break;
1904
- }
1905
- case 'nodemeshchange': {
1906
- var index = -1;
1907
- for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
1908
- if (index != -1) {
1909
- var node = nodes[index];
1910
- if (meshes[message.event.newMeshId] == null) {
1911
- // We don't see the new mesh, remove this device
1912
-
1913
- // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
1914
- if (currentNode == node) { if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); } currentNode = null; }
1915
- nodes.splice(index, 1);
1916
- masterUpdate(4 | 16);
1917
- } else {
1918
- // We see the new mesh, move this device
1919
- node.meshid = message.event.newMeshId;
1920
- node.meshnamel = meshes[message.event.newMeshId].name.toLowerCase();
1921
- masterUpdate(1 | 2 | 4);
1922
- }
1923
- refreshDevice(message.event.nodeid);
1924
- } else {
1925
- // This is a new device, add it.
1926
- var node = message.event.node;
1927
- if (!meshes[node.meshid]) break; // This is a node for a mesh we don't know. Happens when we are site administrator, we get all messages.
1928
- node.namel = node.name.toLowerCase();
1929
- if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
1930
- node.meshnamel = meshes[node.meshid].name.toLowerCase();
1931
- node.state = 0;
1932
- if (!node.icon) node.icon = 1;
1933
- node.ident = ++nodeShortIdent;
1934
- if (nodes == null) { }
1935
- nodes.push(node);
1936
-
1937
- // Web page update
1938
- masterUpdate(1 | 2 | 4 | 16);
1939
- }
1940
- break;
1941
- }
1942
- case 'nodeconnect': {
1943
- // Indicated a node has changed connectivity state
1944
- var index = -1;
1945
- for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
1946
- if (index != -1) {
1947
- var node = nodes[index];
1948
-
1949
- // Event the connection change if needed
1950
- var n = getstore('notifications', 0); // Account notification settings
1951
-
1952
- // Per-group notification settings
1953
- if (message.event.meshid && userinfo.links && userinfo.links[message.event.meshid] && userinfo.links[message.event.meshid].notify) {
1954
- n |= userinfo.links[message.event.meshid].notify;
1955
- }
1956
-
1957
- // Show the notification
1958
- if (n & 2) {
1959
- if (((node.conn & 1) == 0) && ((message.event.conn & 1) != 0)) { addNotification({ text: 'Agent connected', title: node.name, icon: node.icon, nodeid: node._id }); }
1960
- if (((node.conn & 2) == 0) && ((message.event.conn & 2) != 0)) { addNotification({ text: 'Intel AMT detected', title: node.name, icon: node.icon, nodeid: node._id }); }
1961
- if (((node.conn & 4) == 0) && ((message.event.conn & 4) != 0)) { addNotification({ text: 'Intel AMT CIRA connected', title: node.name, icon: node.icon, nodeid: node._id }); }
1962
- }
1963
- if (n & 4) {
1964
- if (((node.conn & 1) != 0) && ((message.event.conn & 1) == 0)) { addNotification({ text: 'Agent disconnected', title: node.name, icon: node.icon, nodeid: node._id }); }
1965
- if (((node.conn & 2) != 0) && ((message.event.conn & 2) == 0)) { addNotification({ text: 'Intel AMT not detected', title: node.name, icon: node.icon, nodeid: node._id }); }
1966
- if (((node.conn & 4) != 0) && ((message.event.conn & 4) == 0)) { addNotification({ text: 'Intel AMT CIRA disconnected', title: node.name, icon: node.icon, nodeid: node._id }); }
1967
- }
1968
-
1969
- // Change the node connection state
1970
- node.conn = message.event.conn;
1971
- node.pwr = message.event.pwr;
1972
-
1973
- // Web page update
1974
- masterUpdate(4 | 16);
1975
- refreshDevice(node._id);
1976
- }
1977
- break;
1978
- }
1979
- case 'wssessioncount': {
1980
- // Update the active web socket session count for a user
1981
- if (wssessions != null) {
1982
- if (message.event.count == 0 && wssessions['user/' + domain + '/' + message.event.username.toLowerCase()]) {
1983
- delete wssessions['user/' + domain + '/' + message.event.username.toLowerCase()];
1984
- } else {
1985
- wssessions['user/' + domain + '/' + message.event.username.toLowerCase()] = message.event.count;
1986
- }
1987
- updateUsers();
1988
- }
1989
- break;
1990
- }
1991
- case 'clearevents': {
1992
- events = [];
1993
- masterUpdate(32);
1994
- break;
1995
- }
1996
- case 'login': {
1997
- // Update the last login time
1998
- if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) {
1999
- users['user/' + domain + '/' + message.event.username.toLowerCase()].login = Math.floor(new Date(message.event.time).getTime() / 1000);
2000
- }
2001
- break;
2002
- }
2003
- case 'scanamtdevice': {
2004
- // Populate the Intel AMT scan dialog box with the result of the RMCP scan
2005
- if ((xxdialogMode == null) || (!Q('dp1range')) || (Q('dp1range').value != message.event.range)) return;
2006
- var x = '';
2007
- if (message.event.results == null) {
2008
- // The scan could not occur because of an error. Likely the user range was invalid.
2009
- x = '<div style=width:100%;text-align:center;margin-top:12px>Unable to scan this address range.</div><div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>Sample IP range values<br />192.168.0.100<br />192.168.1.0/24<br />192.167.0.1-192.168.0.100</div>';
2010
- } else {
2011
- // Go thru all the results and populate the dialog box
2012
- amtScanResults = message.event.results;
2013
- for (var i in message.event.results) {
2014
- var r = message.event.results[i], shortname = r.hostname;
2015
- if (shortname.length > 20) { shortname = shortname.substring(0, 20) + '...'; }
2016
- var str = '<b title="' + EscapeHtml(r.hostname) + '">' + EscapeHtml(shortname) + '</b> - v' + r.ver;
2017
- if (r.state == 2) { if (r.tls == 1) { str += ' with TLS.'; } else { str += ' without TLS.'; } } else { str += ' not activated.'; }
2018
- x += '<div style=width:100%;margin-bottom:2px;background-color:lightgray><div style=padding:4px><div style=display:inline-block;margin-right:5px><input class=DevScanCheckbox name=dp1checkbox tag="' + EscapeHtml(i) + '" type=checkbox onclick=addAmtScanToMeshCheckbox() /></div><div class=j1 style=display:inline-block></div><div style=display:inline-block;margin-left:5px;overflow-x:auto;white-space:nowrap>' + str + '</div></div></div>';
2019
- }
2020
- // If no results where found, display a nice message
2021
- if (x == '') { x = '<div style=width:100%;text-align:center;margin-top:12px>Scan returned no results.</div><div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>Sample IP range values<br />192.168.0.100<br />192.168.1.0/24<br />192.167.0.1-192.168.0.100</div>'; }
2022
- }
2023
- // Set the html in the dialog box and re-enable the scan button
2024
- QH('dp1results', x);
2025
- QE('dp1range', true);
2026
- QE('dp1rangebutton', true);
2027
- break;
2028
- }
2029
- case 'notify': {
2030
- var n = { text: message.event.value, title: message.event.title, icon: message.event.icon };
2031
- if (message.event.tag != null) { n.tag = message.event.tag; }
2032
- addNotification(n);
2033
- break;
2034
- }
2035
- case 'stopped': { // Server is stopping.
2036
- // Disconnect
2037
- //console.log(message.msg);
2038
- break;
2039
- }
2040
- default:
2041
- //console.log('Unknown message.event.action', message.event.action);
2042
- break;
2043
- }
2044
- break;
2045
- }
2046
- case 'createInviteLink': { // Agent installation invitation link
2047
- if (xxdialogTag != message.meshid) break;
2048
- var servername = serverinfo.name;
2049
- if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
2050
- var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
2051
- var url;
2052
- if (serverinfo.https == true) {
2053
- var portStr = (serverinfo.port == 443) ? '' : (":" + serverinfo.port);
2054
- url = "https://" + servername + portStr + domainUrl + "agentinvite?c=" + message.cookie;
2055
- } else {
2056
- var portStr = (serverinfo.port == 80) ? '' : (":" + serverinfo.port);
2057
- url = "http://" + servername + portStr + domainUrl + "agentinvite?c=" + message.cookie;
2058
- }
2059
- Q('agentInvitationLink').href = url;
2060
- var t = message.expire + ' hour' + addLetterS(message.expire);
2061
- if (message.expire == 24) { t = '1 day'; }
2062
- if (message.expire == 168) { t = '1 week'; }
2063
- if (message.expire == 5040) { t = '1 month'; }
2064
- if (message.expire == 0) { t = 'Unlimited'; }
2065
- QH('agentInvitationLink', 'Invitation Link (' + t + ')');
2066
- QV('agentInvitationLinkDiv', true);
2067
- break;
2068
- }
2069
- case 'stopped': { // Server is stopping.
2070
- // Disconnect
2071
- autoReconnect = false;
2072
- QH('p0span', message.msg);
2073
- break;
2074
- }
2075
- default:
2076
- console.log('Unknown message.action', message.action);
2077
- break;
2078
- }
2079
- }
2080
-
2081
- //
2082
- // MY DEVICES
2083
- //
2084
-
2085
- function onRealNameCheckBox() {
2086
- showRealNames = Q('RealNameCheckBox').checked;
2087
- putstore("showRealNames", showRealNames ? 1 : 0);
2088
- masterUpdate(6);
2089
- return;
2090
- }
2091
-
2092
- function onDeviceViewChange(i) {
2093
- if (i != null) { Q('viewselect').value = i; }
2094
- for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
2095
- Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
2096
- putstore("_deviceView", Q('viewselect').value);
2097
- putstore("_viewsize", Q('sizeselect').value);
2098
- masterUpdate(4);
2099
- setTimeout("masterUpdate(512)", 200);
2100
- }
2101
-
2102
- function ondockeypress(e) {
2103
- setSessionActivity();
2104
- if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) {
2105
- // Check what keys we are allows to send
2106
- if (currentNode != null) {
2107
- var mesh = meshes[currentNode.meshid];
2108
- var meshrights = mesh.links[userinfo._id].rights;
2109
- var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
2110
- if (inputAllowed == false) return false;
2111
- var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
2112
- if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
2113
- }
2114
- return desktop.m.handleKeys(e);
2115
- }
2116
- if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { return terminal.m.TermHandleKeys(e); }
2117
- if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) return agentConsoleHandleKeys(e);
2118
- if (!xxdialogMode && xxcurrentView == 4) {
2119
- if (e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
2120
- var processed = 0;
2121
- if (e.key) {
2122
- if (e.key.length === 1 && userSearchFocus == 0) { Q('UserSearchInput').value = ((Q('UserSearchInput').value + e.key)); processed = 1; }
2123
- if (e.keyCode == 8 && userSearchFocus == 0) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = x.substring(0, x.length - 1); processed = 1; }
2124
- if (e.keyCode == 27) { Q('UserSearchInput').value = ''; processed = 1; }
2125
- } else {
2126
- if (e.charCode != 0 && userSearchFocus == 0) { Q('UserSearchInput').value = ((Q('UserSearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
2127
- }
2128
- if (processed > 0) { if (processed == 1) { onUserSearchInputChanged(); } return haltEvent(e); }
2129
- }
2130
- if (xxdialogMode || xxcurrentView != 1) return;
2131
- if (e.ctrlKey == true && e.charCode == 96) {
2132
- showRealNames = !showRealNames;
2133
- Q('RealNameCheckBox').value = showRealNames;
2134
- putstore("showRealNames", showRealNames ? 1 : 0);
2135
- masterUpdate(6)
2136
- return;
2137
- }
2138
- if (e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
2139
- if (Q('viewselect').value < 3) {
2140
- var processed = 0;
2141
- if (e.key) {
2142
- if (e.key.length === 1 && searchFocus == 0) { Q('SearchInput').value = ((Q('SearchInput').value + e.key)); processed = 1; }
2143
- if (e.keyCode == 8 && searchFocus == 0) { var x = Q('SearchInput').value; Q('SearchInput').value = x.substring(0, x.length - 1); processed = 1; }
2144
- if (e.keyCode == 27) { Q('SearchInput').value = ''; processed = 1; }
2145
- } else {
2146
- if (e.charCode != 0 && searchFocus == 0) { Q('SearchInput').value = ((Q('SearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
2147
- }
2148
- if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
2149
- }
2150
- if (Q('viewselect').value == 3) {
2151
- if (e.key) {
2152
- if (e.key.length === 1 && mapSearchFocus == 0) { Q('mapSearchLocation').value = ((Q('mapSearchLocation').value + e.key)); processed = 1; }
2153
- //if (e.keyCode == 8 && mapSearchFocus == 0) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = x.substring(0, x.length - 1); processed = 1; }
2154
- if (e.keyCode == 27) { Q('mapSearchLocation').value = ''; mapCloseSearchWindow(); processed = 1; }
2155
- if (e.keyCode == 13) { getSearchLocation(); }
2156
- } else {
2157
- if (e.charCode != 0 && mapSearchFocus == 0) { Q('mapSearchLocation').value = ((Q('mapSearchLocation').value + String.fromCharCode(e.charCode))); processed = 1; }
2158
- }
2159
- }
2160
- }
2161
-
2162
- function ondockeydown(e) {
2163
- setSessionActivity();
2164
- if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) {
2165
- // Check what keys we are allows to send
2166
- if (currentNode != null) {
2167
- var mesh = meshes[currentNode.meshid];
2168
- var meshrights = mesh.links[userinfo._id].rights;
2169
- var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
2170
- if (inputAllowed == false) return false;
2171
- var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
2172
- if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
2173
- }
2174
- return desktop.m.handleKeyDown(e);
2175
- }
2176
- if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { terminal.m.TermHandleKeyDown(e); if ((e.keyCode >= 37) && (e.keyCode <= 40)) { haltEvent(e); } }
2177
- if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { haltEvent(e); return false; } // F5 Refresh on files
2178
- if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) { return agentConsoleHandleKeys(e); }
2179
- if (!xxdialogMode && xxcurrentView == 4) {
2180
- if (e.keyCode === 8 && userSearchFocus == 0) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
2181
- if (e.keyCode === 27) { Q('UserSearchInput').value = ''; processed = 1; }
2182
- if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
2183
- }
2184
- if (xxdialogMode || xxcurrentView != 1 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
2185
- var processed = 0;
2186
- if (Q('viewselect').value < 3) {
2187
- if (e.keyCode === 8 && searchFocus == 0) { var x = Q('SearchInput').value; Q('SearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
2188
- if (e.keyCode === 27) { Q('SearchInput').value = ''; processed = 1; }
2189
- if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
2190
- }
2191
- if (Q('viewselect').value == 3) {
2192
- if (e.keyCode === 8 && mapSearchFocus == 0) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = (x.substring(0, x.length - 1)); processed = 1; }
2193
- if (e.keyCode === 27) { Q('mapSearchLocation').value = ''; mapCloseSearchWindow(); processed = 1; }
2194
- }
2195
- }
2196
-
2197
- function ondockeyup(e) {
2198
- setSessionActivity();
2199
- if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) {
2200
- // Check what keys we are allows to send
2201
- if (currentNode != null) {
2202
- var mesh = meshes[currentNode.meshid];
2203
- var meshrights = mesh.links[userinfo._id].rights;
2204
- var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
2205
- if (inputAllowed == false) return false;
2206
- var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
2207
- if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
2208
- }
2209
- return desktop.m.handleKeyUp(e);
2210
- }
2211
- if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { return terminal.m.TermHandleKeyUp(e); }
2212
- if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { p13folderup(9999); haltEvent(e); return false; } // F5 Refresh on files
2213
- if (!xxdialogMode && xxcurrentView == 4) { if ((e.keyCode === 8 && searchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
2214
- if (xxdialogMode && e.keyCode == 27) { dialogclose(0); }
2215
- if (xxdialogMode || xxcurrentView != 0 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
2216
- if (Q('viewselect').value < 3) { if ((e.keyCode === 8 && searchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
2217
- if (Q('viewselect').value == 3) { if ((e.keyCode === 8 && mapSearchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
2218
- }
2219
-
2220
- //function ondocfocus() { }
2221
- function ondocblur() { if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) { return desktop.m.handleReleaseKeys(); } }
2222
-
2223
- // Highlights the device being hovered
2224
- function devMouseHover(element, over) {
2225
- setSessionActivity();
2226
- var view = Q('viewselect').value;
2227
- if (view == 1) {
2228
- var e = element.children[1].children[1];
2229
- e.children[0].classList.remove('g1s');
2230
- e.children[1].classList.remove('e2s');
2231
- e.children[2].classList.remove('g2s');
2232
- if (over == 1) {
2233
- e.children[0].classList.add('g1s');
2234
- e.children[1].classList.add('e2s');
2235
- e.children[2].classList.add('g2s');
2236
- }
2237
- } else if (view == 2) {
2238
- var e = element;
2239
- e.children[2].classList.remove('g1s');
2240
- e.children[4].classList.remove('e2s');
2241
- e.children[3].classList.remove('g2s');
2242
- if (over == 1) {
2243
- e.children[2].classList.add('g1s');
2244
- e.children[4].classList.add('e2s');
2245
- e.children[3].classList.add('g2s');
2246
- }
2247
- }
2248
- }
2249
-
2250
- var deviceHeaderId = 0;
2251
- var deviceHeaderTotal = 0;
2252
- var deviceHeadersTitles = {};
2253
- var deviceHeaderCount;
2254
- var deviceHeaders = {};
2255
- var oldviewmode = 0;
2256
- function updateDevices() {
2257
- if (nodes == null) { return; }
2258
- var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, view = Q('viewselect').value, groups = {}, groupCount = {};
2259
- QV('xdevices', view < 4);
2260
- QV('xdevicesmap', view == 4);
2261
- QV('devListToolbar', view < 3);
2262
- QV('kvmListToolbar', view == 3);
2263
- QV('devMapToolbar', view == 4);
2264
- QV('devListToolbarSize', view == 3);
2265
- QV('NoMeshesPanel', meshcount == 0);
2266
- //QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0));
2267
- QV('devListToolbarViewIcons', (meshcount != 0) && (nodes.length > 0));
2268
- QV('devListToolbarSort', (meshcount != 0) && (nodes.length > 0) && (view < 4));
2269
- if ((meshcount == 0) || (nodes.length == 0)) { view = 1; sort = 0; }
2270
- if (view == 4) {
2271
- setTimeout( function() { if (xxmap.map != null) { xxmap.map.updateSize(); } }, 200);
2272
- // TODO
2273
- } else {
2274
- // 3 wide, list view or desktop view
2275
- deviceHeaderId = 0;
2276
- deviceHeaderCount = {};
2277
- deviceHeaderTotal = 0;
2278
- deviceHeaders = {};
2279
- deviceHeadersTitles = {};
2280
- var kvmDivs = [];
2281
-
2282
- // Perform node sort
2283
- if (sort == 0) { nodes.sort(meshSort); }
2284
- else if (sort == 1) { nodes.sort(powerSort); }
2285
- else if (sort == 2) { if (showRealNames == true) { nodes.sort(deviceHostSort); } else { nodes.sort(deviceSort); } }
2286
-
2287
- // Save the list of currently checked nodeid's
2288
- var checkedNodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
2289
- for (var i=0;i<elements.length;i++) { if (elements[i].checked) { checkedNodeids.push(elements[i].value); } }
2290
- if ((oldviewmode < 3) && (view == 3)) { multiDesktopFilter = checkedNodeids; }
2291
- else if ((oldviewmode == 3) && (view < 3)) { checkedNodeids = multiDesktopFilter; }
2292
-
2293
- // Compute the width of the device view.
2294
- var totalDeviceViewWidth = Q('column_l').clientWidth - 60;
2295
- var deviceBoxWidth = Math.floor(totalDeviceViewWidth / 301);
2296
- deviceBoxWidth = 301 + Math.floor((totalDeviceViewWidth - (deviceBoxWidth * 301)) / deviceBoxWidth);
2297
-
2298
- if (view == 2) {
2299
- r += '<table style=width:100%;margin-top:4px cellpadding=0 cellspacing=0><th style=color:gray><th style=color:gray;width:120px>User<th style=color:gray;width:120px>Address<th style=color:gray;width:100px>Connectivity'; //<th style=color:gray;width:100px>State';
2300
- }
2301
-
2302
- // Go thru the list of nodes and display them
2303
- for (var i in nodes) {
2304
- var node = nodes[i];
2305
- if (node.v == false) continue;
2306
- var mesh2 = meshes[node.meshid], meshlinks = mesh2.links[userinfo._id];
2307
- if (meshlinks == null) continue;
2308
- var meshrights = meshlinks.rights;
2309
- if ((view == 3) && (mesh2.mtype == 1)) continue;
2310
- if (sort == 0) {
2311
- // Mesh header
2312
- if (node.meshid != current) {
2313
- deviceHeaderSet();
2314
- var extra = '';
2315
- if (view == 2) { r += '<tr><td colspan=5>'; }
2316
- if (meshes[node.meshid].mtype == 1) { extra = '<span class=devHeaderx>, Intel® AMT only</span>'; }
2317
- if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
2318
- if (view == 2) { r += '<div>'; }
2319
- r += '<div class=DevSt style=width:100%;padding-top:4px><span style=float:right>';
2320
- r += '<span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx></span>' + extra;
2321
- r += '</span><span id=MxMESH tabindex=0 style=cursor:pointer onclick=gotoMesh("' + node.meshid + '") onkeypress="if (event.key==\'Enter\') gotoMesh(\'' + node.meshid + '\')">' + EscapeHtml(meshes[node.meshid].name) + '</span>' + getMeshActions(mesh2, meshrights) + '</div>';
2322
- if (view == 2) { r += '</div>'; }
2323
- current = node.meshid;
2324
- displayedMeshes[current] = 1;
2325
- c = 0;
2326
- }
2327
- } else if (sort == 1) {
2328
- // Power header
2329
- var pwr = node.pwr?node.pwr:0;
2330
- if (pwr !== current) {
2331
- deviceHeaderSet();
2332
- if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
2333
- r += '<div class=DevSt style=width:100%;padding-top:4px><span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx style=float:right></span><span>' + PowerStateStr2(node.pwr) + '</span></div>';
2334
- current = pwr;
2335
- c = 0;
2336
- }
2337
- } else if (sort == 2) {
2338
- // Device header
2339
- if (current == null) { current = '1'; }
2340
- }
2341
-
2342
- count++;
2343
- var title = EscapeHtml(node.name);
2344
- if (title.length == 0) { title = '<i>None</i>'; }
2345
- if ((node.rname != null) && (node.rname.length > 0)) { title += " / " + EscapeHtml(node.rname); }
2346
- var name = EscapeHtml(node.name);
2347
- if (showRealNames == true && node.rname != null) name = EscapeHtml(node.rname);
2348
- if (name.length == 0) { name = '<i>None</i>'; }
2349
-
2350
- // Node
2351
- var icon = node.icon;
2352
- if ((!node.conn) || (node.conn == 0)) { icon += ' gray'; }
2353
- if (view == 1) {
2354
- r += '<div id=devs onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=display:inline-block;width:' + deviceBoxWidth + 'px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox></div><div style=height:100%;cursor:pointer tabindex=0 onclick=gotoDevice(\'' + node._id + '\',null,null,event) onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',null,null,event)"><div class="i' + icon + '" style=width:50px;float:left></div><div style=height:100%><div class=g1></div><div class=e2><div class=e1 style=width:' + (deviceBoxWidth - 100) + 'px title="' + title + '">' + name + '</div><div>' + NodeStateStr(node) + '</div></div><div class=g2></div></div></div></div>';
2355
- } else if (view == 2) {
2356
- var states = [];
2357
- if (node.conn) {
2358
- if ((node.conn & 1) != 0) { states.push('<span title="Mesh agent is connected and ready for use.">Agent</span>'); }
2359
- if ((node.conn & 2) != 0) { states.push('<span title="Intel® AMT CIRA is connected and ready for use.">CIRA</span>'); }
2360
- else if ((node.conn & 4) != 0) { states.push('<span title="Intel® AMT is routable.">AMT</span>'); }
2361
- if ((node.conn & 8) != 0) { states.push('<span title="Mesh agent is reachable using another agent as relay.">Relay</span>'); }
2362
- }
2363
- r += '<tr><td><div id=devs class=bar18 tabindex=0 onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=height:18px;width:100%;font-size:medium onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',null,null,event)">';
2364
- r += '<div class=deviceBarCheckbox><input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox></div>';
2365
- r += '<div class=deviceBarIcon onclick=gotoDevice(\'' + node._id + '\',null,null,event)><div class=\"j' + icon + '\" style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
2366
- r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
2367
- r += '<div style=cursor:pointer;font-size:14px title="' + title + '" onclick=gotoDevice(\'' + node._id + '\',null,null,event)><span style=width:300px>' + name + '</span></div></div></td>';
2368
- r += '<td style=text-align:center>' + getUserShortStr(node);
2369
- r += '<td style=text-align:center>' + (node.ip != null ? node.ip : '');
2370
- r += '<td style=text-align:center>' + states.join(' + ');
2371
- //r += '<td style=text-align:center>' + (node.pwr != null ? powerStateStrings[node.pwr] : '');
2372
- r += '</tr>';
2373
- } else if ((view == 3) && (node.conn & 1) && (((meshrights & 8) || (meshrights & 256)) != 0) && ((node.agent.caps & 1) != 0)) { // Check if we have rights and agent is capable of KVM.
2374
- if ((multiDesktopFilter.length == 0) || (multiDesktopFilter.indexOf('devid_' + node._id) >= 0)) {
2375
- r += '<div id=devs style=display:inline-block;margin:1px;background-color:lightgray;border-radius:5px;position:relative><div tabindex=0 style=padding:3px;cursor:pointer onclick=gotoDevice(\'' + node._id + '\',11,null,event) onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',11,null,event)">';
2376
- //r += '<input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox style=float:left>';
2377
- r += '<div class="j' + icon + '" style=width:16px;float:left></div> ' + name + '</div>';
2378
- r += '<span onclick=gotoDevice(\'' + node._id + '\',null,null,event)></span><div id=xkvmid_' + node._id.split('/')[2] + '><div id=skvmid_' + node._id.split('/')[2] + ' tabindex=0 style="position:absolute;color:white;left:5px;top:27px;text-shadow:0px 0px 5px #000;z-index:1000;cursor:default" onclick=toggleKvmDevice(\'' + node._id + '\') onkeypress="if (event.key==\'Enter\') toggleKvmDevice(\'' + node._id + '\')">Disconnected</div></div>';
2379
- r += '</div>';
2380
- kvmDivs.push(node._id);
2381
- }
2382
- }
2383
-
2384
- // If we are displaying devices by group, put the device in the right group.
2385
- if ((sort == 3) && (r != '')) {
2386
- if (node.tags) {
2387
- for (var j in node.tags) {
2388
- var tag = node.tags[j];
2389
- if (groups[tag] == null) { groups[tag] = r; groupCount[tag] = 1; } else { groups[tag] += r; groupCount[tag] += 1; }
2390
- if (view == 3) break;
2391
- }
2392
- }
2393
- r = '';
2394
- }
2395
-
2396
- deviceHeaderTotal++;
2397
- if (typeof deviceHeaderCount[node.state] == 'undefined') { deviceHeaderCount[node.state] = 1; } else { deviceHeaderCount[node.state]++; }
2398
- }
2399
-
2400
- // If displaying devices by groups, sort the group names and display the devices.
2401
- if (sort == 3) {
2402
- var groupNames = [];
2403
- for (var i in groups) { groupNames.push(i); }
2404
- groupNames.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); });
2405
- for (var j in groupNames) {
2406
- var i = groupNames[j]; r += '<div class=DevSt style=width:100%;padding-top:4px><span class=devHeaderx style=float:right>' + groupCount[i] + ' node' + ((groupCount[i] > 1) ? 's' : '') + '</span><span>' + i + '</span></div>' + groups[i];
2407
- }
2408
- }
2409
-
2410
- // If there is nothing to display, explain the problem
2411
- if ((r == '') && (meshcount > 0) && (Q('SearchInput').value != '')) {
2412
- if (sort == 3) {
2413
- r = '<div style="margin:30px">No devices are included in any groups, click on a device\'s \"Groups\" to add to a group.</div>';
2414
- } else {
2415
- r = '<div style="margin:30px">No devices matching this search.</div>';
2416
- }
2417
- }
2418
-
2419
- if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding
2420
-
2421
- // Display all empty device groups, we need to do this because users can add devices to these at any time.
2422
- if ((sort == 0) && (Q('SearchInput').value == '') && (view < 3)) {
2423
- for (var i in meshes) {
2424
- var mesh = meshes[i], meshlink = mesh.links[userinfo._id];
2425
- if (meshlink != null) {
2426
- var meshrights = meshlink.rights;
2427
- if (displayedMeshes[mesh._id] == null) {
2428
- if ((current != '') && (r != '')) { r += '</tr></table>'; }
2429
- r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span><span>';
2430
- r += getMeshActions(mesh, meshrights);
2431
- r += '</span></td></tr><tr>';
2432
- if (mesh.mtype == 1) {
2433
- r += '<td><div style=padding:10px><i>No Intel® AMT devices in this mesh';
2434
- if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addDeviceToMesh(\"' + mesh._id + '\"\')>add one</a>'; }
2435
- }
2436
- if (mesh.mtype == 2) {
2437
- r += '<td><div style=padding:10px><i>No devices in this mesh';
2438
- if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addAgentToMesh(\"' + mesh._id + '\")\'>add one</a>'; }
2439
- }
2440
- r += '.</i></div></td>';
2441
- current = mesh._id;
2442
- count++;
2443
- }
2444
- }
2445
- }
2446
- }
2447
- r += '</tr></table><div style=height:1px></div>'; // This height of 1 div fixes a problem in Linux firefox browsers
2448
-
2449
- // Add a "Add Device Group" option
2450
- r += '<div style=border-top-style:solid;border-top-width:1px;border-top-color:#DDDDDD;cursor:pointer;font-size:10px>';
2451
- if ((view < 3) && (sort == 0) && (meshcount > 0) && ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 64) == 0))) {
2452
- r += '<a href=# onclick="return account_createMesh()" title="Create a new group of devices." style=cursor:pointer>Add Device Group</a> ';
2453
- }
2454
- if ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 128) == 0)) {
2455
- r += '<a href=# onclick=\'return p10showMeshCmdDialog(0)\' style=cursor:pointer title="Download MeshCmd, a command line tool that performs many functions.">MeshCmd</a> ';
2456
- if (navigator.platform.toLowerCase() == 'win32') { r += '<a href=# onclick=\'return p10showMeshRouterDialog()\' style=cursor:pointer title="Download MeshCentral Router, a TCP port mapping tool.">Router</a> '; }
2457
- }
2458
- r += '</div><br/>';
2459
-
2460
- QH('xdevices', r);
2461
- deviceHeaderSet();
2462
-
2463
- // Re-check nodeid's
2464
- var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
2465
- for (var i=0;i<elements.length;i++) { elements[i].checked = (checkedNodeids.indexOf(elements[i].value) >= 0); }
2466
-
2467
- for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
2468
- for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
2469
- p1updateInfo();
2470
-
2471
- // Take care of KVM surfaces in desktop view mode
2472
- if (view == 3) {
2473
- // Figure out and adjust the size to fill the width of the div
2474
- var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
2475
- //var realw = vsize.x + 2, tw = Q('xdevices').clientWidth - 30, xw = Math.floor(tw / realw);
2476
- var realw = vsize.x + 2, tw = totalDeviceViewWidth - 5, xw = Math.floor(tw / realw);
2477
- xw = realw + Math.floor((tw - (xw * realw)) / xw);
2478
- vsize.y = vsize.y * (xw / vsize.x);
2479
- vsize.x = xw;
2480
-
2481
- for (var i in multiDesktop) { multiDesktop[i].xxdelete = true; }
2482
- for (var i in kvmDivs) {
2483
- var id = kvmDivs[i], shortid = id.split('/')[2], desk = multiDesktop[id];
2484
- if (desk != null) {
2485
- // This device already has a canvas, use it.
2486
- desk.m.CanvasId.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
2487
- Q('xkvmid_' + shortid).appendChild(desk.m.CanvasId);
2488
- delete desk.xxdelete;
2489
- QH('skvmid_' + shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][((desk.m.State == null)?desk.m.state:desk.m.State)]);
2490
- } else {
2491
- var node = getNodeFromId(id);
2492
- if ((desktopNode == node) && (desktop != null)) { // Check if the main desktop is this device, if it is, use that.
2493
- // This device already has a canvas, use it.
2494
- var c = desktop.m.CanvasId;
2495
- c.setAttribute('id', 'kvmid_' + shortid);
2496
- c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
2497
- c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
2498
- c.removeAttribute('onmousedown');
2499
- c.removeAttribute('onmouseup');
2500
- c.removeAttribute('onmousemove');
2501
- Q('xkvmid_' + shortid).appendChild(c);
2502
- QH('skvmid_' + shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][((desktop.m.State == null)?desktop.m.state:desktop.m.State)]);
2503
- if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
2504
- desktop.shortid = shortid;
2505
- desktop.onStateChanged = onMultiDesktopStateChange;
2506
- multiDesktop[id] = desktop;
2507
- desktop = desktopNode = currentNode = null;
2508
- // Setup a replacement desktop
2509
- QH('DeskParent', '<canvas id="Desk" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
2510
- } else {
2511
- // This is a new device, create a canvas for it.
2512
- var c = document.createElement('canvas');
2513
- c.setAttribute('id', 'kvmid_' + shortid);
2514
- c.setAttribute('width', 640);
2515
- c.setAttribute('height', 480);
2516
- c.setAttribute('oncontextmenu', 'return false');
2517
- c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
2518
- c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
2519
- try { Q('xkvmid_' + shortid).appendChild(c); } catch (ex) {}
2520
- // Check if we need to auto-connect
2521
- if (Q('autoConnectDesktopCheckbox').checked == true) { setTimeout(function() { connectMultiDesktop(node, 1); }, 100); }
2522
- }
2523
- }
2524
- }
2525
- for (var i in multiDesktop) {
2526
- // If a device is no longer viewed, disconnect it.
2527
- if (multiDesktop[i].xxdelete == true) { multiDesktop[i].Stop(); delete multiDesktop[i]; }
2528
- else if (debugmode && multiDesktop[i].m && multiDesktop[i].m.onScreenSizeChange) {
2529
- mdeskAdjust(multiDesktop[i].m, multiDesktop[i].m.ScreenWidth, multiDesktop[i].m.ScreenHeight, multiDesktop[i].m.CanvasId); // Adjust screen size change
2530
- }
2531
- }
2532
- deskAdjust();
2533
- } else {
2534
- disconnectAllKvmFunction();
2535
- Q('autoConnectDesktopCheckbox').checked = false;
2536
- }
2537
- }
2538
- oldviewmode = view;
2539
- }
2540
-
2541
- function toggleKvmDevice(nodeid) {
2542
- var node = getNodeFromId(nodeid), mesh = meshes[node.meshid], meshrights = mesh.links[userinfo._id].rights;
2543
- if ((meshrights & 8) || (meshrights & 256)) { // Requires remote control rights or desktop view only rights
2544
- //var conn = 0;
2545
- //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)
2546
- if (node.conn & 1) { connectMultiDesktop(node, 1); }
2547
- }
2548
- }
2549
-
2550
- function getUserShortStr(node) {
2551
- if (node == null || node.users == null || node.users.length == 0) return '';
2552
- if (node.users.length > 1) { return '<span title="' + EscapeHtml(node.users.join(', ')) + '">' + node.users.length + ' users</span>'; }
2553
- var u = node.users[0], su = u, i = u.indexOf('\\');
2554
- if (i > 0) { su = u.substring(i + 1); }
2555
- su = EscapeHtml(su);
2556
- if (su.length > 15) { su = su.substring(0, 14) + '…'; }
2557
- return '<span title="' + EscapeHtml(u) + '">' + su + '</span>';
2558
- }
2559
-
2560
- function autoConnectDesktops() { if (Q('autoConnectDesktopCheckbox').checked == true) { connectAllKvmFunction(); } }
2561
- function connectAllKvmFunction() { for (var i in nodes) { if (multiDesktop[nodes[i]._id] == null) { toggleKvmDevice(nodes[i]._id); } } }
2562
- function disconnectAllKvmFunction() { for (var nodeid in multiDesktop) { multiDesktop[nodeid].Stop(); } multiDesktop = {}; }
2563
- function onMultiDesktopStateChange(desk, state) { try { QH('skvmid_' + desk.shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][state]); } catch (ex) {} }
2564
-
2565
- function showMultiDesktopSettings() {
2566
- QV('d7amtkvm', false);
2567
- QV('d7meshkvm', true);
2568
- d7bitmapquality.value = multidesktopsettings.quality;
2569
- d7bitmapscaling.value = multidesktopsettings.scaling;
2570
- if (multidesktopsettings.framerate) { d7framelimiter.value = multidesktopsettings.framerate; } else { d7framelimiter.value = 1000; }
2571
- setDialogMode(7, "Remote Desktop Settings", 3, showMultiDesktopSettingsChanged);
2572
- }
2573
-
2574
- function showMultiDesktopSettingsChanged() {
2575
- multidesktopsettings.quality = d7bitmapquality.value;
2576
- multidesktopsettings.scaling = d7bitmapscaling.value;
2577
- multidesktopsettings.framerate = d7framelimiter.value;
2578
- localStorage.setItem('multidesktopsettings', JSON.stringify(multidesktopsettings));
2579
- // Make changes to all current connections
2580
- for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
2581
- }
2582
-
2583
- function connectMultiDesktop(node, contype) {
2584
- var nodeid = node._id, shortid = nodeid.split('/')[2];
2585
- var desk = multiDesktop[nodeid];
2586
- if (desk == null) {
2587
- if (Q('kvmid_' + shortid) == null) return; // Check if this device is being displayed, if not, exit now.
2588
- if (contype == 2) {
2589
- // Setup the Intel AMT remote desktop
2590
- if ((node.intelamt.user == null) || (node.intelamt.user == '')) { return; }
2591
- desk = CreateAmtRedirect(CreateAmtRemoteDesktop('kvmid_' + shortid), authCookie);
2592
- desk.shortid = shortid;
2593
- //desk.debugmode = debugmode;
2594
- desk.onStateChanged = onMultiDesktopStateChange;
2595
- desk.m.bpp = 1;
2596
- desk.m.useZRLE = true;
2597
- desk.m.showmouse = true;
2598
- desk.m.onKvmData = function (data) { console.log('KVM Data received in multi-desktop mode, this is not supported.'); }; // KVM Data Channel not supported in multi-desktop right now.
2599
- //desk.m.onScreenSizeChange = deskAdjust;
2600
- if (debugmode > 0) { desk.m.onScreenSizeChange = mdeskAdjust; } // Multi-Desktop Adjust
2601
- desk.Start(nodeid, 16994, '*', '*', 0);
2602
- desk.contype = 2;
2603
- multiDesktop[nodeid] = desk;
2604
- } else if (contype == 1) {
2605
- // Setup the Mesh Agent remote desktop
2606
- desk = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('kvmid_' + shortid), serverPublicNamePort, authCookie, domainUrl);
2607
- desk.shortid = shortid;
2608
- desk.attemptWebRTC = attemptWebRTC;
2609
- desk.onStateChanged = onMultiDesktopStateChange;
2610
- //desk.onConsoleMessageChange = function () { console.log('CONSOLEMSG:', desk.consoleMessage); }
2611
- desk.m.CompressionLevel = multidesktopsettings.quality;
2612
- desk.m.ScalingLevel = multidesktopsettings.scaling;
2613
- desk.m.FrameRateTimer = multidesktopsettings.framerate;
2614
- //desk.m.onDisplayinfo = deskDisplayInfo;
2615
- //desk.m.onScreenSizeChange = deskAdjust;
2616
- if (debugmode > 0) { desk.m.onScreenSizeChange = mdeskAdjust; } // Multi-Desktop Adjust
2617
- desk.Start(nodeid);
2618
- desk.contype = 1;
2619
- multiDesktop[nodeid] = desk;
2620
- }
2621
- } else {
2622
- // Disconnect and clean up the remote desktop
2623
- desk.Stop();
2624
- delete multiDesktop[nodeid];
2625
- }
2626
- }
2627
-
2628
- function getMeshActions(mesh, meshrights) {
2629
- if ((meshrights & 4) == 0) return '';
2630
- var r = '';
2631
- if ((features & 1024) == 0) { // If CIRA is allowed
2632
- r += ' <a href=# style=cursor:pointer;font-size:10px title="Add a new Intel® AMT computer that is located on the internet." onclick=\'return addCiraDeviceToMesh(\"' + mesh._id + '\")\'>Add CIRA</a>';
2633
- }
2634
- if (mesh.mtype == 1) {
2635
- if ((features & 1) == 0) { // If not WAN-Only
2636
- r += ' <a href=# style=cursor:pointer;font-size:10px title="Add a new Intel® AMT computer that is located on the local network." onclick=\'return addDeviceToMesh(\"' + mesh._id + '\")\'>Add Local</a>';
2637
- r += ' <a href=# style=cursor:pointer;font-size:10px title="Add a new Intel® AMT computer by scanning the local network." onclick=\'return addAmtScanToMesh(\"' + mesh._id + '\")\'>Scan Network</a>';
2638
- }
2639
- if (mesh.amt && (mesh.amt.type == 2)) { // CCM activation
2640
- r += ' <a href=# style=cursor:pointer;font-size:10px title="Perform Intel AMT client control mode (CCM) activation." onclick=\'return showCcmActivation(\"' + mesh._id + '\")\'>Activation</a>';
2641
- } else if (mesh.amt && (mesh.amt.type == 3) && ((features & 0x00100000) != 0)) { // ACM activation
2642
- r += ' <a href=# style=cursor:pointer;font-size:10px title="Perform Intel AMT admin control mode (ACM) activation." onclick=\'return showAcmActivation(\"' + mesh._id + '\")\'>Activation</a>';
2643
- }
2644
- }
2645
- if (mesh.mtype == 2) {
2646
- r += ' <a href=# style=cursor:pointer;font-size:10px title="Add a new computer to this mesh by installing the mesh agent." onclick=\'return addAgentToMesh(\"' + mesh._id + '\")\'>Add Agent</a>';
2647
- r += ' <a href=# style=cursor:pointer;font-size:10px title="Invite someone to install the mesh agent on this mesh." onclick=\'return inviteAgentToMesh(\"' + mesh._id + '\")\'>Invite</a>';
2648
- }
2649
- return r;
2650
- }
2651
-
2652
- function addDeviceToMesh(meshid) {
2653
- if (xxdialogMode) return false;
2654
- var mesh = meshes[meshid];
2655
- var x = "Add a new Intel® AMT device to device group \"" + EscapeHtml(mesh.name) + "\".<br /><br />";
2656
- x += addHtmlValue('Device Name', '<input id=dp1devicename style=width:230px maxlength=32 autocomplete=off onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
2657
- x += addHtmlValue('Hostname', '<input id=dp1hostname style=width:230px maxlength=32 autocomplete=off placeholder="Same as device name" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
2658
- x += addHtmlValue('Username', '<input id=dp1username style=width:230px maxlength=32 autocomplete=off placeholder="admin" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
2659
- x += addHtmlValue('Password', '<input id=dp1password type=password style=width:230px autocomplete=off maxlength=32 onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
2660
- x += addHtmlValue('Security', '<select id=dp1tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
2661
- setDialogMode(2, "Add Intel® AMT device", 3, addDeviceToMeshEx, x, meshid);
2662
- validateDeviceToMesh();
2663
- Q('dp1devicename').focus();
2664
- return false;
2665
- }
2666
-
2667
- // Intel AMT CCM Activation
2668
- function showCcmActivation(meshid) {
2669
- if (xxdialogMode) return false;
2670
- var servername = serverinfo.name, mesh = meshes[meshid];
2671
- if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
2672
- var url, domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
2673
- if (serverinfo.https == true) {
2674
- var portStr = (serverinfo.port == 443) ? '' : (":" + serverinfo.port);
2675
- url = "wss://" + servername + portStr + domainUrl;
2676
- } else {
2677
- var portStr = (serverinfo.port == 80) ? '' : (":" + serverinfo.port);
2678
- url = "ws://" + servername + portStr + domainUrl;
2679
- }
2680
- var x = "Perform Intel AMT client control mode (CCM) activation to group \"" + EscapeHtml(mesh.name) + "\" by downloading the MeshCMD tool and running it like this:<br /><br />";
2681
- x += '<textarea readonly=readonly style=width:100%;resize:none;height:100px;overflow:auto;font-size:12px readonly>meshcmd amtccm --url ' + url + 'amtactivate?id=' + meshid.split('/')[2] + ' --serverhttpshash ' + serverinfo.tlshash + '</textarea>';
2682
- setDialogMode(2, "Intel® AMT activation", 9, null, x);
2683
- Q('idx_dlgOkButton').focus();
2684
- return false;
2685
- }
2686
-
2687
- // Intel AMT ACM Activation
2688
- function showAcmActivation(meshid) {
2689
- if (xxdialogMode) return false;
2690
- var servername = serverinfo.name, mesh = meshes[meshid];
2691
- if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
2692
- var url, domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
2693
- if (serverinfo.https == true) {
2694
- var portStr = (serverinfo.port == 443) ? '' : (":" + serverinfo.port);
2695
- url = "wss://" + servername + portStr + domainUrl;
2696
- } else {
2697
- var portStr = (serverinfo.port == 80) ? '' : (":" + serverinfo.port);
2698
- url = "ws://" + servername + portStr + domainUrl;
2699
- }
2700
- var x = "Perform Intel AMT admin control mode (ACM) activation to group \"" + EscapeHtml(mesh.name) + "\" by downloading the MeshCMD tool and running it like this:<br /><br />";
2701
- x += '<textarea readonly=readonly style=width:100%;resize:none;height:100px;overflow:auto;font-size:12px readonly>meshcmd amtacm --url ' + url + 'amtactivate?id=' + meshid.split('/')[2] + ' --serverhttpshash ' + serverinfo.tlshash + '</textarea>';
2702
- if (serverinfo.amtAcmFqdn != null) {
2703
- x += '<div style=margin-top:8px>Intel AMT will need to be set with a Trusted FQDN in MEBx or have a wired LAN on the network: <b>' + serverinfo.amtAcmFqdn.join(', ') + '</b></div>';
2704
- }
2705
- setDialogMode(2, "Intel® AMT activation", 9, null, x);
2706
- Q('idx_dlgOkButton').focus();
2707
- return false;
2708
- }
2709
-
2710
- // Display the Intel AMT scanning dialog box
2711
- function addAmtScanToMesh(meshid) {
2712
- if (xxdialogMode) return false;
2713
- var x = "Enter a range of IP addresses to scan for Intel AMT devices.<br /><br />";
2714
- x += addHtmlValue('IP Range', '<input id=dp1range style=width:184px value="192.168.1.0/24" onkeyup=addAmtScanToMeshKeyUp(event) /><input id=dp1rangebutton type=button value=Scan onclick=addAmtScanToMeshButton()></input>');
2715
- x += '<div id=dp1results style="width:100%;height:200px;background-color:white;border:1px gray solid;overflow-y:scroll"></div>';
2716
- setDialogMode(2, "Scan for Intel® AMT devices", 3, addAmtScanToMeshEx, x, meshid);
2717
- QE('idx_dlgOkButton', false);
2718
- QH('dp1results', '<div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>Sample IP range values<br />192.168.0.100<br />192.168.1.0/24<br />192.167.0.1-192.168.0.100</div>');
2719
- focusTextBox('dp1range');
2720
- return false;
2721
- }
2722
-
2723
- function addAmtScanToMeshKeyUp(e) {
2724
- if (e.keyCode == 13) { haltEvent(e); addAmtScanToMeshButton(); }
2725
- }
2726
-
2727
- // Called when OK is pressed on the Intel AMT scanning box
2728
- function addAmtScanToMeshEx(button, meshid) {
2729
- var elements = document.getElementsByClassName("DevScanCheckbox"), checkcount = 0;
2730
- for (var i=0;i<elements.length;i++) {
2731
- if (elements[i].checked) {
2732
- var ipaddr = elements[i].getAttribute('tag');
2733
- var amtinfo = amtScanResults[ipaddr];
2734
- meshserver.send({ action: 'addamtdevice', meshid: meshid, devicename: ipaddr, hostname: amtinfo.hostname, amtusername: '', amtpassword: '', amttls: amtinfo.tls });
2735
- }
2736
- }
2737
- }
2738
-
2739
- // If the user presses the "Scan" button on the Intel AMT scanning dialog box, start a scan.
2740
- function addAmtScanToMeshButton() {
2741
- QE('dp1range', false);
2742
- QE('dp1rangebutton', false);
2743
- QH('dp1results', '<div style=width:100%;text-align:center;margin-top:12px>Scanning...</div>');
2744
- meshserver.send({ action: 'scanamtdevice', range: Q('dp1range').value });
2745
- }
2746
-
2747
- // Called when a scanned computer is checked or unchecked.
2748
- function addAmtScanToMeshCheckbox() {
2749
- var elements = document.getElementsByClassName("DevScanCheckbox"), checkcount = 0;
2750
- for (var i=0;i<elements.length;i++) { if (elements[i].checked) checkcount++; }
2751
- QE('idx_dlgOkButton', checkcount > 0);
2752
- }
2753
-
2754
- function addCiraDeviceToMesh(meshid) {
2755
- if (xxdialogMode) return false;
2756
- var mesh = meshes[meshid];
2757
-
2758
- // Replace non alphabetic characters (@ and $) with 'X' because MPS username cannot accept it.
2759
- var meshidx = meshid.split('/')[2].replace(/\@/g, 'X').replace(/\$/g, 'X');
2760
-
2761
- var y = '<select id=dlgAddCiraSel onclick=dlgAddCiraSelClick() style=width:230px><option value=0>MeshCommander Script</option><option value=1>Manual Username/Password</option>';
2762
- 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.
2763
-
2764
- var x = '';
2765
- x += addHtmlValue('Setup Method', y);
2766
- x += '<hr>';
2767
-
2768
- // Setup CIRA using a MeshCommander script (Pretty Simple)
2769
- x += "<div id=dlgAddCira0>To add a new Intel® AMT device to device group \"" + EscapeHtml(mesh.name) + "\" with CIRA, download the following script files and use <a href='http://meshcommander.com' rel='noreferrer noopener' target='_blank'>MeshCommander</a> to run the script to configure computers.<br /><br />";
2770
- x += addHtmlValue('Setup CIRA', '<a href="mescript.ashx?type=1&meshid=' + meshidx.substring(0, 16) + '" download>cira_setup.mescript</a>');
2771
- x += addHtmlValue('Cleanup CIRA', '<a href="mescript.ashx?type=2" download>cira_clean.mescript</a>');
2772
- x += "</div>";
2773
-
2774
- // Setup CIRA with user/pass authentication (Somewhat difficult)
2775
- x += "<div id=dlgAddCira1 style=display:none>To add a new Intel® AMT device to device group \"" + EscapeHtml(mesh.name) + "\" with CIRA, load the following certificate as trusted root within Intel AMT";
2776
- if (serverinfo.mpspass) { x += " and authenticate to the server using this username and password.<br /><br />"; } else { x += " and authenticate to the server using this username and any password.<br /><br />"; }
2777
- x += addHtmlValue('Root Certificate', '<a href="MeshServerRootCert.cer" download>Root Certificate File</a>');
2778
- x += addHtmlValue('Username', '<input style=width:230px readonly value="' + meshidx.substring(0, 16) + '" />');
2779
- if (serverinfo.mpspass) { x += addHtmlValue('Password', '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpspass) + '" />'); }
2780
- if (serverinfo != null) { x += addHtmlValue('MPS Server', '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
2781
- x += "</div>";
2782
-
2783
- // Setup CIRA with certificate authentication (Really difficult, only if TLS offload is not used)
2784
- if ((features & 16) == 0) {
2785
- x += "<div id=dlgAddCira2 style=display:none>To add a new Intel® AMT device to device group \"" + EscapeHtml(mesh.name) + "\" with CIRA, load the following certificate as trusted root within Intel AMT, authenticate using a client certificate with the following common name and connect to the following server.<br /><br />";
2786
- x += addHtmlValue('Root Certificate', '<a href="MeshServerRootCert.cer" download>Root Certificate File</a>');
2787
- x += addHtmlValue('Organization', '<input style=width:230px readonly value="' + meshidx + '" />');
2788
- if (serverinfo != null) { x += addHtmlValue('MPS Server', '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
2789
- x += "</div>";
2790
- }
2791
-
2792
- setDialogMode(2, "Add Intel® AMT CIRA device", 2, null, x, 'fileDownload');
2793
- Q('dlgAddCiraSel').focus();
2794
- return false;
2795
- }
2796
-
2797
- function dlgAddCiraSelClick() {
2798
- var val = Q('dlgAddCiraSel').value;
2799
- QV('dlgAddCira0', val == 0);
2800
- QV('dlgAddCira1', val == 1);
2801
- QV('dlgAddCira2', val == 2);
2802
- }
2803
-
2804
- // Return true is the input string looks like an email address
2805
- function checkEmail(str) {
2806
- var x = str.split('@');
2807
- var ok = ((x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2));
2808
- if (ok == true) { var y = x[1].split('.'); for (var i in y) { if (y[i].length == 0) { ok = false; } } }
2809
- return ok;
2810
- }
2811
-
2812
- function inviteAgentToMesh(meshid) {
2813
- if (xxdialogMode) return false;
2814
- var x = '', mesh = meshes[meshid];
2815
- if (features & 64) {
2816
- x += addHtmlValue('Invitation Type', '<select id=d2InviteType onchange=d2ChangedInviteType() style=width:236px><option value=0>Link invitation</option><option value=1>Email invitation</option></select>') + "<hr />";
2817
- x += "<div id=emailInviteDiv style=display:none>Invite someone to install the mesh agent. An email with be sent with the link to the mesh agent installation for the \"" + EscapeHtml(mesh.name) + "\" device group.<br /><br />";
2818
- x += addHtmlValue('Name (optional)', '<input id=agentInviteName value="" style=width:230px maxlength=64 />');
2819
- x += addHtmlValue('Email', '<input id=agentInviteEmail style=width:230px placeholder="example@email.com" onkeyup=validateAgentInvite()></input>');
2820
- x += addHtmlValue('Operating System', '<select id=agentInviteNameOs onchange=d2ChangedInviteType() style=width:236px><option value=4>Send installation link</option><option value=0 selected>Any supported</option><option value=1>Windows only</option><option value=3>Apple MacOS only</option><option value=2>Linux only</option></select>');
2821
- x += '<div id=d2agentexpirediv>';
2822
- x += addHtmlValue('Link Expiration', '<select id=agentInviteExpire style=width:236px><option value=1>1 hour</option><option value=8>8 hours</option><option value=24>1 day</option><option value=168>1 week</option><option value=5040>1 month</option><option value=0>Unlimited</option></select>');
2823
- x += '</div>';
2824
- x += addHtmlValue('Installation Type', '<select id=agentInviteType style=width:236px><option value=0>Background and interactive</option><option value=2>Background only</option><option value=1>Interactive only</option></select>');
2825
- x += addHtmlValue('Message<br />(optional)', '<textarea id=agentInviteMessage value="" style=width:230px;height:100px;resize:none maxlength=1024 /></textarea>');
2826
- x += '</div>';
2827
- }
2828
- x += '<div id=urlInviteDiv>Invite someone to install the mesh agent by sharing an invitation link. This link points the user to installation instructions for the \"' + EscapeHtml(mesh.name) + '\" device group. The link is public and no account for this server is needed.<br /><br />';
2829
- x += addHtmlValue('Link Expiration', '<select id=d2inviteExpire style=width:236px onchange=d2RequestInvitationLink()><option value=1>1 hour</option><option value=8>8 hours</option><option value=24>1 day</option><option value=168>1 week</option><option value=5040>1 month</option><option value=0>Unlimited</option></select>');
2830
- x += '<div id=agentInvitationLinkDiv style="text-align:center;font-size:large;margin:16px;display:none"><a href=# id=agentInvitationLink target="_blank" style=cursor:pointer></a> <img src=images/link4.png height=10 width=10 title="Copy link to clipboard" style=cursor:pointer onclick=d2CopyInviteToClip()></div></div>';
2831
- setDialogMode(2, "Invite", 3, performAgentInvite, x, meshid);
2832
- if (features & 64) { Q('d2InviteType').focus(); d2ChangedInviteType(); } else { Q('d2inviteExpire').focus(); validateAgentInvite(); }
2833
- d2RequestInvitationLink();
2834
- return false;
2835
- }
2836
-
2837
- function d2RequestInvitationLink() {
2838
- meshserver.send({ action: 'createInviteLink', meshid: xxdialogTag, expire: parseInt(Q('d2inviteExpire').value), flags: 0 });
2839
- }
2840
-
2841
- function d2ChangedInviteType() {
2842
- QV('urlInviteDiv', Q('d2InviteType').value == 0);
2843
- QV('d2agentexpirediv', Q('agentInviteNameOs').value == 4);
2844
- QV('emailInviteDiv', Q('d2InviteType').value == 1);
2845
- validateAgentInvite();
2846
- }
2847
-
2848
- function d2CopyInviteToClip() { copyTextToClip(Q('agentInvitationLink').href); }
2849
-
2850
- function validateAgentInvite() {
2851
- if ((features & 64) && (Q('d2InviteType').value == 1)) {
2852
- QE('idx_dlgOkButton', checkEmail(Q('agentInviteEmail').value));
2853
- QV('idx_dlgCancelButton', true);
2854
- } else {
2855
- QE('idx_dlgOkButton', true);
2856
- QV('idx_dlgCancelButton', false);
2857
- }
2858
- }
2859
-
2860
- function performAgentInvite(button, meshid) {
2861
- if ((features & 64) && (Q('d2InviteType').value == 1)) {
2862
- meshserver.send({ action: 'inviteAgent', meshid: meshid, email: Q('agentInviteEmail').value, name: Q('agentInviteName').value, os: Q('agentInviteNameOs').value, flags: Q('agentInviteType').value, msg: Q('agentInviteMessage').value, expire: parseInt(Q('agentInviteExpire').value) });
2863
- }
2864
- }
2865
-
2866
- function addAgentToMesh(meshid) {
2867
- if (xxdialogMode) return false;
2868
- var mesh = meshes[meshid], x = '', installType = 0;
2869
- x += addHtmlValue('Operating System', '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>Windows</option><option value=1>Linux / BSD</option><option value=2>Apple MacOS</option><option value=3>Windows (UnInstall)</option><option value=4>Linux / BSD (UnInstall)</option></select>');
2870
- x += '<div id=aginsTypeDiv>';
2871
- x += addHtmlValue('Installation Type', '<select id=aginsType onchange=addAgentToMeshClick() style=width:236px><option value=0>Background & interactive</option><option value=2>Background only</option><option value=1>Interactive only</option></select>');
2872
- x += '</div><hr>';
2873
-
2874
- // \/:*?"<>|
2875
- var meshfilename = mesh.name
2876
- meshfilename = meshfilename.split('\\').join('').split('/').join('').split(':').join('').split('*').join('').split('?').join('').split('"').join('').split('<').join('').split('>').join('').split('|').join('').split(' ').join('').split('\'').join('');
2877
-
2878
- // Windows agent install
2879
- //x += "<div id=agins_windows>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and configuration file and install the agent on the computer to manage.<br /><br />";
2880
- x += "<div id=agins_windows>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and install it the computer to manage. This agent has server and device group information embedded within it.<br /><br />";
2881
- x += addHtmlValue('Mesh Agent', '<a id=aginsw32lnk href="meshagents?id=3&meshid=' + meshid.split('/')[2] + '&installflags=0" download onclick="setDialogMode(0)" title="32bit version of the MeshAgent">Windows (.exe)</a> <img src=images/link4.png height=10 width=10 title="Copy Windows 32bit agent URL to clipboard" style=cursor:pointer onclick=copyAgentUrl("meshagents?id=3&meshid=' + meshid.split('/')[2] + '&installflags=",1)>');
2882
- x += addHtmlValue('Mesh Agent', '<a id=aginsw64lnk href="meshagents?id=4&meshid=' + meshid.split('/')[2] + '&installflags=0" download onclick="setDialogMode(0)" title="64bit version of the MeshAgent">Windows x64 (.exe)</a> <img src=images/link4.png height=10 width=10 title="Copy Windows 64bit agent URL to clipboard" style=cursor:pointer onclick=copyAgentUrl("meshagents?id=4&meshid=' + meshid.split('/')[2] + '&installflags=",1)>');
2883
- if (debugmode > 0) { x += addHtmlValue('Settings File', '<a id=aginswmshlnk href="meshsettings?id=' + meshid.split('/')[2] + '&installflags=0" rel="noreferrer noopener" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>'); }
2884
- x += "</div>";
2885
-
2886
- // Linux agent install
2887
- x += "<div id=agins_linux style=display:none>To add a computer to " + EscapeHtml(mesh.name) + " run the following command. Root credentials will be needed.<br />";
2888
- x += '<textarea id=agins_linux_area rows=2 cols=20 readonly=readonly style=width:100%;resize:none;height:120px;overflow:scroll;font-size:12px readonly></textarea>';
2889
- x += "<div style='font-size:x-small'>* For BSD, run \"pkg install wget sudo bash\" first.</div></div>";
2890
-
2891
- // MacOS agent install
2892
- x += "<div id=agins_osx style=display:none>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and install it the computer to manage. This agent installer has server and device group information embedded within it.<br /><br />";
2893
- x += addHtmlValue('Mesh Agent', '<a href="meshosxagent?id=16&meshid=' + meshid.split('/')[2] + '" rel="noreferrer noopener" target="_blank" title="64bit version of MacOS Mesh Agent">MacOS Agent (64bit)</a> <img src=images/link4.png height=10 width=10 title="Copy MacOS agent URL to clipboard" style=cursor:pointer onclick=copyAgentUrl("meshosxagent?id=16&meshid=' + meshid.split('/')[2] + '",0)>');
2894
- x += "</div>";
2895
-
2896
- // Windows agent uninstall
2897
- x += "<div id=agins_windows_un style=display:none>To remove a mesh agent, download the file below, run it and click \"uninstall\".<br /><br />";
2898
- x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3" download onclick="setDialogMode(0)" title="32bit version of the MeshAgent">Windows (.exe)</a>');
2899
- x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=4" download onclick="setDialogMode(0)" title="64bit version of the MeshAgent">Windows x64 (.exe)</a>');
2900
- x += "</div>";
2901
-
2902
- // Linux agent uninstall
2903
- x += "<div id=agins_linux_un style=display:none>To remove a mesh agent, run the following command. Root credentials will be needed.<br />";
2904
- x += '<textarea id=agins_linux_area_un rows=2 cols=20 readonly=readonly style=width:100%;resize:none;height:120px;overflow:scroll;font-size:12px readonly></textarea>';
2905
- x += "</div>";
2906
-
2907
- setDialogMode(2, "Add Mesh Agent", 2, null, x, 'fileDownload');
2908
- var servername = serverinfo.name;
2909
- if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
2910
- var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
2911
-
2912
- if (serverinfo.https == true)
2913
- {
2914
- var portStr = (serverinfo.port == 443)?'':(":" + serverinfo.port);
2915
- if ((features & 0x2000) == 0)
2916
- {
2917
- Q('agins_linux_area').value = "(wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-check-certificate -O ./meshinstall.sh || wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://" + servername + portStr + domainUrlNoSlash + " '" + meshid.split('/')[2] + "'\r\n";
2918
- Q('agins_linux_area_un').value = "(wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-check-certificate -O ./meshinstall.sh || wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
2919
- }
2920
- else
2921
- {
2922
- // Server asked that agent be installed to preferably not use a HTTP proxy.
2923
- Q('agins_linux_area').value = "wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://" + servername + portStr + domainUrlNoSlash + " '" + meshid.split('/')[2] + "'\r\n";
2924
- Q('agins_linux_area_un').value = "wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
2925
- }
2926
- }
2927
- else
2928
- {
2929
- var portStr = (serverinfo.port == 80) ? '' : (":" + serverinfo.port);
2930
- if ((features & 0x2000) == 0)
2931
- {
2932
- Q('agins_linux_area').value = "(wget http://" + servername + portStr + domainUrl + "meshagents?script=1 -O ./meshinstall.sh || wget http://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh http://" + servername + portStr + domainUrlNoSlash + " '" + meshid.split('/')[2] + "'\r\n";
2933
- Q('agins_linux_area_un').value = "(wget http://" + servername + portStr + domainUrl + "meshagents?script=1 -O ./meshinstall.sh || wget http://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
2934
- }
2935
- else
2936
- {
2937
- // Server asked that agent be installed to preferably not use a HTTP proxy.
2938
- Q('agins_linux_area').value = "wget http://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh http://" + servername + portStr + domainUrlNoSlash + " '" + meshid.split('/')[2] + "'\r\n";
2939
- Q('agins_linux_area_un').value = "wget http://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
2940
- }
2941
- }
2942
- Q('aginsSelect').focus();
2943
- addAgentToMeshClick();
2944
- return false;
2945
- }
2946
-
2947
- function copyAgentUrl(url,addflag) {
2948
- var servername = serverinfo.name;
2949
- if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
2950
- var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
2951
- var portStr = (serverinfo.port == 443) ? '' : (":" + serverinfo.port);
2952
- var c = "https://" + servername + portStr + domainUrl + url;
2953
- if (addflag == 1) c += Q('aginsType').value;
2954
- copyTextToClip(c);
2955
- }
2956
-
2957
- function addAgentToMeshClick() {
2958
- var v = Q('aginsSelect').value;
2959
- QV('agins_windows', v == 0);
2960
- QV('agins_linux', v == 1);
2961
- QV('agins_osx', v == 2);
2962
- QV('agins_windows_un', v == 3);
2963
- QV('agins_linux_un', v == 4);
2964
- QV('aginsTypeDiv', v == 0);
2965
-
2966
- // Fix the links if needed
2967
- Q('aginsw32lnk').href = (Q('aginsw32lnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value;
2968
- Q('aginsw64lnk').href = (Q('aginsw64lnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value;
2969
- if (debugmode > 0) { Q('aginswmshlnk').href = (Q('aginswmshlnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value; }
2970
- }
2971
-
2972
- function validateDeviceToMesh() {
2973
- QE('idx_dlgOkButton', (Q('dp1devicename').value.length > 0) && (passwordcheck(Q('dp1password').value)));
2974
- }
2975
-
2976
- function addDeviceToMeshEx(button, meshid) {
2977
- var amtuser = Q('dp1username').value;
2978
- if (amtuser == '') amtuser = 'admin';
2979
- var host = Q('dp1hostname').value;
2980
- if (host == '') host = Q('dp1devicename').value;
2981
- meshserver.send({ action: 'addamtdevice', meshid: meshid, devicename: Q('dp1devicename').value, hostname: host, amtusername: amtuser, amtpassword: Q('dp1password').value, amttls: Q('dp1tls').value });
2982
- }
2983
-
2984
- function deviceHeaderSet() {
2985
- if (deviceHeaderId == 0) { deviceHeaderId = 1; return; }
2986
- deviceHeaders["DevxHeader" + deviceHeaderId] = deviceHeaderTotal + ((deviceHeaderTotal == 1) ? ' node' : ' nodes');
2987
- //var title = '';
2988
- //for (x in deviceHeaderCount) { if (title.length > 0) title += ', '; title += deviceHeaderCount[x] + ' ' + PowerStateStr2(x); }
2989
- //deviceHeadersTitles["DevxHeader" + deviceHeaderId] = title;
2990
- deviceHeaderId++;
2991
- deviceHeaderCount = {};
2992
- deviceHeaderTotal = 0;
2993
- }
2994
-
2995
- var powerStateStrings = ['', '<span title="Device is powered on.">Powered</span>', '<span title="Device is in sleep state (S1).">Sleeping</span>', '<span title="Device is in sleep state (S2).">Sleeping</span>', '<span title="Device is in deep sleep state (S3).">Deep Sleep</span>', '<span title="Device is in hibernating state (S4).">Hibernating</span>', '<span title="Device is in powered off state (S5).">Soft-Off</span>', '<span title="Device is detected but power state could not be obtained.">Present</span>'];
2996
- var powerStateStrings2 = ['', 'Device is powered', 'Device is in sleep state (S1)', 'Device is in sleep state (S2)', 'Device is in deep sleep state (S3)', 'Device is hibernating (S4)', 'Device is in soft-off state (S5)', 'Device is present, but power state cannot be determined'];
2997
- var powerColorTable = ['pwsTransparent', 'pwsBlack', 'pwsBlue', 'pwsBlue2', 'pwsLightblue', 'pwsBlueviolet', 'pwsDarkgreen', 'pwsLightseagreen', 'pwsLightseagreen2'];
2998
- function NodeStateStr(node) {
2999
- var states = [];
3000
- if (node.state > 0 && node.state < powerStatetable.length) state.push(powerStatetable[node.state]);
3001
- if (node.conn) {
3002
- if ((node.conn & 1) != 0) { states.push('<span title="Mesh agent is connected and ready for use.">Agent</span>'); }
3003
- if ((node.conn & 2) != 0) { states.push('<span title="Intel® AMT CIRA is connected and ready for use.">CIRA</span>'); }
3004
- else if ((node.conn & 4) != 0) { states.push('<span title="Intel® AMT is routable.">Intel® AMT</span>'); }
3005
- if ((node.conn & 8) != 0) { states.push('<span title="Mesh agent is reachable using another agent as relay.">Relay</span>'); }
3006
- }
3007
- if ((node.pwr != null) && (node.pwr != 0)) { states.push(powerStateStrings[node.pwr]); }
3008
- return states.join(', ');
3009
- }
3010
-
3011
- function PowerStateStr(x) {
3012
- if (x < powerStatetable.length) return powerStatetable[x];
3013
- return '';
3014
- }
3015
-
3016
- function PowerStateStr2(x) {
3017
- if ((x != 0) && (x < powerStatetable.length)) return powerStatetable[x];
3018
- return 'Unknown';
3019
- }
3020
-
3021
- function selectallButtonFunction() {
3022
- var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
3023
- for (var i=0;i<elements.length;i++) { if (elements[i].checked === true) checkcount++; }
3024
- for (var i=0;i<elements.length;i++) { elements[i].checked = (checkcount == 0); }
3025
- p1updateInfo();
3026
- }
3027
-
3028
- function p1updateInfo() {
3029
- var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
3030
- for (var i=0;i<elements.length;i++) { if (elements[i].checked === true) { checkcount++; } }
3031
- if (checkcount > 0) {
3032
- QE('GroupActionButton', true);
3033
- Q('SelectAllButton').value = 'Select None';
3034
- QV('cxmgroupsplit', true);
3035
- QV('cxmdesktop', true);
3036
- } else {
3037
- QE('GroupActionButton', false);
3038
- Q('SelectAllButton').value = 'Select All';
3039
- QV('cxmgroupsplit', false);
3040
- QV('cxmdesktop', false);
3041
- }
3042
- }
3043
-
3044
- function groupActionFunction() {
3045
- var x = "Select an operation to perform on all selected devices. Actions will be performed only with proper rights.<br /><br />";
3046
- x += addHtmlValue('Operation', '<select id=d2groupop><option value=100>Wake-up devices</option><option value=4>Sleep devices</option><option value=3>Reset devices</option><option value=2>Power off devices</option><option value=102>Move to device group</option><option value=101>Delete devices</option></select>');
3047
- setDialogMode(2, "Group Action", 3, groupActionFunctionEx, x);
3048
- }
3049
-
3050
- // Get the list of checked devices, removes any duplicates.
3051
- function getCheckedDevices() {
3052
- var nodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
3053
- for (var i=0;i<elements.length;i++) { if (elements[i].checked) { if (elements[i].value) { var nid = elements[i].value.substring(6); if (nodeids.indexOf(nid) == -1) { nodeids.push(nid); } } } }
3054
- return nodeids;
3055
- }
3056
-
3057
- function groupActionFunctionEx() {
3058
- var op = Q('d2groupop').value;
3059
- if (op == 100) {
3060
- // Group wake
3061
- meshserver.send({ action: 'wakedevices', nodeids: getCheckedDevices() });
3062
- } else if (op == 101) {
3063
- // Group delete, ask for confirmation
3064
- var x = "Confirm delete selected devices(s)?<br /><br />";
3065
- x += "<label><input id=d2check type=checkbox onchange=d2groupActionFunctionDelEx() />Confirm</label>";
3066
- setDialogMode(2, "Delete Nodes", 3, groupActionFunctionDelEx, x);
3067
- QE('idx_dlgOkButton', false);
3068
- } else if (op == 102) {
3069
- // Move computers to a different group
3070
- p10showChangeGroupDialog(getCheckedDevices());
3071
- } else {
3072
- // Power operation
3073
- meshserver.send({ action: 'poweraction', nodeids: getCheckedDevices(), actiontype: op });
3074
- }
3075
- }
3076
-
3077
- function d2groupActionFunctionDelEx() { QE('idx_dlgOkButton', Q('d2check').checked); }
3078
- function groupActionFunctionDelEx() { meshserver.send({ action: 'removedevices', nodeids: getCheckedDevices() }); }
3079
-
3080
- function onSortSelectChange(skipsave) {
3081
- sort = document.getElementById("sortselect").selectedIndex;
3082
- if (!skipsave) { putstore("sort", sort); }
3083
- }
3084
-
3085
- function meshSort(a, b) { if (a.meshnamel > b.meshnamel) return 1; if (a.meshnamel < b.meshnamel) return -1; if (a.meshid == b.meshid) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } return 0; }
3086
- function powerSort(a, b) { var ap = a.pwr?a.pwr:0; var bp = b.pwr?b.pwr:0; if (ap > bp) return -1; if (ap < bp) return 1; if (ap == bp) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } return 0; }
3087
- function deviceSort(a, b) { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; }
3088
- function deviceHostSort(a, b) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; }
3089
- function onSearchFocus(x) { searchFocus = x; }
3090
- function onMapSearchFocus(x) { mapSearchFocus = x; }
3091
- function onUserSearchFocus(x) { userSearchFocus = x; }
3092
- function onConsoleFocus(x) { consoleFocus = x; }
3093
-
3094
- function onSearchInputChanged() {
3095
- var x = Q('SearchInput').value.toLowerCase().trim(); putstore("_search", x);
3096
- var userSearch = null, ipSearch = null, groupSearch = null;
3097
- if (x.startsWith('user:')) { userSearch = x.substring(5); }
3098
- else if (x.startsWith('u:')) { userSearch = x.substring(2); }
3099
- else if (x.startsWith('ip:')) { ipSearch = x.substring(3); }
3100
- else if (x.startsWith('group:')) { groupSearch = x.substring(6); }
3101
- else if (x.startsWith('g:')) { groupSearch = x.substring(2); }
3102
-
3103
- if (x == '') {
3104
- // No search
3105
- for (var d in nodes) { nodes[d].v = true; }
3106
- } else if (ipSearch != null) {
3107
- // IP address search
3108
- for (var d in nodes) { nodes[d].v = ((nodes[d].ip != null) && (nodes[d].ip.indexOf(ipSearch) >= 0)); }
3109
- } else if (groupSearch != null) {
3110
- // Group filter
3111
- for (var d in nodes) { nodes[d].v = (meshes[nodes[d].meshid].name.toLowerCase().indexOf(groupSearch) >= 0); }
3112
- } else if (userSearch != null) {
3113
- // User search
3114
- for (var d in nodes) {
3115
- nodes[d].v = false;
3116
- if (nodes[d].users && nodes[d].users.length > 0) { for (var i in nodes[d].users) { if (nodes[d].users[i].toLowerCase().indexOf(userSearch) >= 0) { nodes[d].v = true; } } }
3117
- }
3118
- } else {
3119
- // Device name search
3120
- try {
3121
- var rs = x.split(/\s+/).join('|'), rx = new RegExp(rs); // In some cases (like +), this can throw an exception.
3122
- for (var d in nodes) {
3123
- nodes[d].v = (rx.test(nodes[d].name.toLowerCase())) || (nodes[d].rnamel != null && rx.test(nodes[d].rnamel.toLowerCase()));
3124
- if ((nodes[d].v == false) && nodes[d].tags) {
3125
- for (var s in nodes[d].tags) {
3126
- if (rx.test(nodes[d].tags[s].toLowerCase())) {
3127
- nodes[d].v = true;
3128
- break;
3129
- } else {
3130
- nodes[d].v = false;
3131
- }
3132
- }
3133
- }
3134
- }
3135
- } catch (ex) { for (var d in nodes) { nodes[d].v = true; } }
3136
- }
3137
- }
3138
-
3139
- var contextelement = null;
3140
- function handleContextMenu(event) {
3141
- hideContextMenu();
3142
- var scrollLeft = (window.pageXOffset !== null) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
3143
- var scrollTop = (window.pageYOffset !== null) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
3144
- var elem = document.elementFromPoint(event.pageX - scrollLeft, event.pageY - scrollTop);
3145
- if (elem && elem != null && elem.id == "MxMESH") {
3146
- contextelement = elem;
3147
- var contextmenudiv = document.getElementById("meshContextMenu");
3148
- contextmenudiv.style.left = event.pageX + "px";
3149
- contextmenudiv.style.top = event.pageY + "px";
3150
- contextmenudiv.style.display = "block";
3151
- } else {
3152
- while (elem && elem != null && elem.id != "devs") { elem = elem.parentElement; }
3153
- if (!elem || elem == null) return true;
3154
- contextelement = elem;
3155
- var contextmenudiv = document.getElementById("contextMenu");
3156
- contextmenudiv.style.left = event.pageX + "px";
3157
- contextmenudiv.style.top = event.pageY + "px";
3158
- contextmenudiv.style.display = "block";
3159
- }
3160
-
3161
- // Get the node and set the menu options
3162
- var nodeid = contextelement.children[1].attributes.onclick.value;
3163
- var node = getNodeFromId(nodeid.substring(12, nodeid.length - 18));
3164
- var mesh = meshes[node.meshid];
3165
- var meshlinks = mesh.links[userinfo._id];
3166
- var meshrights = meshlinks.rights;
3167
- var consoleRights = ((meshrights & 16) != 0);
3168
-
3169
- // Check if we have terminal and file access
3170
- var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0));
3171
- var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0));
3172
-
3173
- QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((meshrights & 8) || (meshrights & 256)));
3174
- QV('cxterminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8) && terminalAccess);
3175
- QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess);
3176
- QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8));
3177
- QV('cxconsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
3178
-
3179
- return haltEvent(event);
3180
- }
3181
-
3182
- function cmaction(action,event) {
3183
- var nodeid = contextelement.children[1].attributes.onclick.value;
3184
- nodeid = nodeid.substring(12, nodeid.length - 18);
3185
- if (action == 7) { Q('viewselect').value = 3; Q('viewselect').onchange(); Q('autoConnectDesktopCheckbox').checked = true; Q('autoConnectDesktopCheckbox').onclick(); } // Multi-Desktop
3186
- if ((action > 0) && (action < 7)) {
3187
- var panel = [0, 10, 12, 11, 13, 16, 15][action]; // (invalid), General, Desktop, Terminal, Files, Events, Console
3188
- if (event && (event.shiftKey == true)) {
3189
- // Open the device in a different tab
3190
- window.open(window.location.origin + '?node=' + nodeid.split('/')[2] + '&viewmode=' + panel + '&hide=16', 'meshcentral:' + nodeid);
3191
- } else {
3192
- // Go to the right panel
3193
- gotoDevice(nodeid, panel);
3194
-
3195
- // If possible, connect...
3196
- var mesh = meshes[currentNode.meshid];
3197
- if ((currentNode.conn & 1) && (mesh.mtype == 2)) {
3198
- if ((panel == 11) && (desktop == null) && (currentNode.agent.caps & 1)) { connectDesktop(null, 1); } // Desktop
3199
- if ((panel == 12) && (terminal == null) && (currentNode.agent.caps & 2)) { connectTerminal(null, 1); } // Terminal
3200
- if ((panel == 13) && (files == null)) { connectFiles(null); } // files
3201
- }
3202
- }
3203
- }
3204
- }
3205
-
3206
- function cmmeshaction(action) {
3207
- var meshid = contextelement.attributes.onclick.value.substring(32, (32 + 69));
3208
- var elements = document.getElementsByClassName("DeviceCheckbox");
3209
- if (action == 1) { for (var i = 0; i < elements.length; i++) { if ( (elements[i].attributes) && (elements[i].attributes['class']['value'].substring(0, 69) == meshid)) { elements[i].checked = true; } } }
3210
- if (action == 2) { for (var i = 0; i < elements.length; i++) { if ( (elements[i].attributes) && (elements[i].attributes['class']['value'].substring(0, 69) == meshid)) { elements[i].checked = false; } } }
3211
- //if (action == 3) { window.location = "multidesktop.aspx?mesh=" + meshid + "&auto=1"; }
3212
- p1updateInfo();
3213
- }
3214
-
3215
- function hideContextMenu() {
3216
- QV('contextMenu', false);
3217
- QV('meshContextMenu', false);
3218
- contextelement = null;
3219
- }
3220
-
3221
- //
3222
- // DEVICES MAP
3223
- //
3224
-
3225
- // Maps code starts from here. Initialize all the variables
3226
- var xxmap = {
3227
- map: null,
3228
- contextmenu: null,
3229
- activeInteractions: [], // Save Modified features in this list
3230
- showindex: 0,
3231
- markersSource: null, // Initialize a Source Vector
3232
- markersLayer: null,
3233
- mapLayer: null, // Create a tile and use OSM source
3234
- mapView: null, // Sets the initial view
3235
- }
3236
-
3237
- // Add a feature for every Node and change style if connection status changes
3238
- function updateMapMarkers(selectedMesh) {
3239
- if ((xxmap != null) && (xxmap.map == null)) { try { loadmap(); } catch (ex) { console.error('loadmap() exception', ex); } }
3240
- if (xxmap == null) return;
3241
- var boundingBox = null;
3242
- for (var i in nodes) {
3243
- try {
3244
- var loc = map_parseNodeLoc(nodes[i]), feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
3245
- if ((loc != null) && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
3246
- var lat = loc[0], lon = loc[1], type = loc[2];
3247
- if (boundingBox == null) { boundingBox = [ lat, lon, lat, lon, 0 ]; } else { if (lat < boundingBox[0]) { boundingBox[0] = lat; } if (lon < boundingBox[1]) { boundingBox[1] = lon; } if (lat > boundingBox[2]) { boundingBox[2] = lat; } if (lon > boundingBox[3]) { boundingBox[3] = lon; } }
3248
- if (feature == null) { addFeature(nodes[i]); boundingBox[4] = 1; } else { updateFeature(nodes[i], feature); feature.setStyle(markerStyle(nodes[i], loc[2])); } // Update Feature
3249
- } else {
3250
- if (feature) { xxmap.markersSource.removeFeature(feature); }
3251
- }
3252
- } catch (ex) { console.error('updateMapMarkers() exception', ex, JSON.stringify(nodes[i])); }
3253
- }
3254
- return boundingBox;
3255
- }
3256
-
3257
- // Show node details on hovering over a feature
3258
- var map_cm_popup = new ol.Overlay({ element: Q('xmap-info-window'), positioning: 'bottom-center', stopEvent: false });
3259
-
3260
- // Edit Marker item
3261
- var map_cm_editMarker = { text: "Modify node location", callback: function (obj) { modifyMarkerloc(obj.data); } };
3262
-
3263
- // Clear Marker item
3264
- var map_cm_clearMarker = { text: "Remove node location", callback: function (obj) {
3265
- meshserver.send({ action: 'changedevice', nodeid: obj.data.a, userloc: [] }); // Clear the user position marker
3266
- }};
3267
-
3268
- // Save Marker item
3269
- var map_cm_saveMarker = { text: "Save node location", callback: function (obj) { saveMarkerloc(obj.data); } };
3270
-
3271
- // Build a context menu for a feature
3272
- var map_cm_nodemenu_items = [
3273
- { text: "General information", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 10); } } },
3274
- { text: "Desktop", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 11); } } },
3275
- { text: "Terminal", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 12); } } },
3276
- { text: "Intel® AMT", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 14); } } },
3277
- '-',
3278
- { text: 'Zoom-in to extent', callback: function(obj) { var coords = obj.data.getGeometry().getCoordinates(); zoomToLocation(coords, 19); } },
3279
- { text: 'Zoom-out to extent', callback: function(obj) { var coords = obj.data.getGeometry().getCoordinates(); zoomToLocation(coords, 2); } }
3280
- ];
3281
-
3282
- // Context menu for clicks other than on feature
3283
- var contextmenu_items = [
3284
- { text: 'Refresh', callback: function () { refreshMap(true, true); } },
3285
- { text: 'Zoom to fit extent', callback: function () { zoomToFitExtent(); } },
3286
- { text: 'Center map here', callback: function(obj) { xxmap.mapView.animate({ center: obj.coordinate } ); } },
3287
- { text: 'Place node here', callback: function(obj) { placeNode(obj.coordinate); } }
3288
- ];
3289
-
3290
- function stringToIntHash(str) {
3291
- var hash = 0, i;
3292
- for (i = 0; i < str.length; i++) { hash = ((hash << 5) - hash) + str.charCodeAt(i); hash |= 0; }
3293
- return hash;
3294
- };
3295
-
3296
- // Get the lat/lon from a node
3297
- function map_parseNodeLoc(node) {
3298
- var loc = null, t = 0;
3299
- if (node.iploc) { loc = node.iploc; t = 1; }
3300
- if (node.wifiloc) { loc = node.wifiloc; t = 2; }
3301
- if (node.gpsloc) { loc = node.gpsloc; t = 3; }
3302
- if (node.userloc) { loc = node.userloc; t = 4; }
3303
- if ((loc == null) || (typeof loc != 'string')) return null;
3304
- loc = loc.split(',');
3305
- if (t == 1) {
3306
- // If this is IP location, randomize the position a little.
3307
- return [ parseFloat(loc[0]) + (stringToIntHash(node._id.substring(0, 20)) / 100000000000), parseFloat(loc[1]) + (stringToIntHash(node._id.substring(20)) / 100000000000), t ];
3308
- } else {
3309
- // Return the real position
3310
- return [ parseFloat(loc[0]), parseFloat(loc[1]), t ];
3311
- }
3312
- }
3313
-
3314
- // Load the entire map
3315
- function loadmap() {
3316
- if (xxmap == null) return;
3317
- if ((features & 0x8000) == 0) { QV('viewselectmapoption', false); QV('devViewButton4', false); xxmap = null; return; } // Geolocation not supported
3318
- try {
3319
- // Initialize a Source Vector
3320
- xxmap.markersSource = new ol.source.Vector();
3321
-
3322
- xxmap.markersLayer = new ol.layer.Vector({
3323
- source: xxmap.markersSource
3324
- });
3325
-
3326
- // Create a tile and use OSM source
3327
- xxmap.mapLayer = new ol.layer.Tile({ source: new ol.source.OSM() });
3328
-
3329
- xxmap.mapView = new ol.View({ // Set the initial view
3330
- center: ol.proj.transform([0, 0], 'EPSG:4326', 'EPSG:3857'),
3331
- zoom: 2,
3332
- minZoom: 2,
3333
- maxZoom: 20,
3334
- extent: ol.proj.transformExtent([-100000, -69.55, 100000, 69.55], 'EPSG:4326', 'EPSG:3857')
3335
- });
3336
-
3337
- xxmap.map = new ol.Map({
3338
- target: 'xdevicesmap',
3339
- layers: [xxmap.mapLayer, xxmap.markersLayer],
3340
- view: xxmap.mapView
3341
- });
3342
-
3343
- xxmap.map.addOverlay(map_cm_popup);
3344
-
3345
- // Goto information tab if a user clicks on a feature
3346
- xxmap.map.on('click', function(evt) {
3347
- var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(feat, layer) { return feat; });
3348
- if (feature) {
3349
- var nodeid = feature.getId();
3350
- if (nodeid != null) { gotoDevice(nodeid, 10); } // Goto general info tab
3351
- else { // For pointer
3352
- var nodeFeatgoto = getCorrespondingFeature(feature); gotoDevice(nodeFeatgoto.getId(), 10);
3353
- }
3354
- }
3355
- });
3356
-
3357
- // On hover feature show the name of the node. Also add pointer style
3358
- xxmap.map.on('pointermove', function(evt) {
3359
- var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(feat, layer) { return feat; });
3360
- if (feature) {
3361
- xxmap.map.getTargetElement().style.cursor = 'pointer';
3362
- var coord = feature.getGeometry().getCoordinates();
3363
- // map_cm_popup.setPosition(evt.coordinate);
3364
- map_cm_popup.setPosition(coord);
3365
- var featid = feature.getId();
3366
- if (featid) {
3367
- QH('xmap-info-window', feature.get('name'));
3368
- } else {
3369
- var nodeFeat = getCorrespondingFeature(feature); // Return the node feature associated to pointer.
3370
- QH('xmap-info-window', nodeFeat.get('name'));
3371
- }
3372
- } else {
3373
- xxmap.map.getTargetElement().style.cursor = '';
3374
- QH('xmap-info-window', '');
3375
- }
3376
- });
3377
-
3378
- // Initialize context menu for openlayers
3379
- var contextmenu = new ContextMenu({
3380
- width: 160,
3381
- defaultItems: false, // defaultItems are Zoom In/Zoom Out
3382
- items: contextmenu_items
3383
- });
3384
-
3385
- // On right click open the context menu
3386
- contextmenu.on("open", function (evt) {
3387
- var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(ft, l){ return ft; });
3388
- xxmap.contextmenu.clear(); //Clear the context menu
3389
- if (feature) {
3390
- var featId = feature.getId();
3391
- if (featId) { addContextMenuItems(feature); } // Node feature will have an id
3392
- else { // If the feature is a pointer, Get its corresponding Node feature
3393
- var nodeFeature = getCorrespondingFeature(feature); //return the node feature associated to pointer.
3394
- if (nodeFeature) { addContextMenuItems(nodeFeature); }
3395
- else{ xxmap.contextmenu.extend(contextmenu_items); }
3396
- }
3397
- }
3398
- else { xxmap.contextmenu.extend(contextmenu_items); }
3399
- });
3400
- if (xxmap.contextmenu == null) { xxmap.contextmenu = contextmenu; }
3401
- xxmap.map.addControl(xxmap.contextmenu);
3402
- //addMeshOptions(); // Adds Mesh names to mesh dropdown
3403
- } catch (ex) {
3404
- console.log(ex);
3405
- QV('viewselectmapoption', false);
3406
- QV('devViewButton4', false);
3407
- xxmap = null;
3408
- }
3409
- }
3410
-
3411
- // Add feature on to Map for a Node
3412
- function addFeature(node, lat, lon) {
3413
- var existingfeature = getModifiedFeature(node._id); // Check if Corresponding feature was Modified ( Modifed feature are in active interactions list)
3414
- if (existingfeature) { xxmap.markersSource.addFeature(existingfeature); } // Add that existing feature
3415
- else { // Add new feature for this node
3416
- if (!lat && !lon) { var loc = map_parseNodeLoc(node); lat = loc[0]; lon = loc[1]; }
3417
-
3418
- // Fix the longiture and send an event to patch the db to correct coordinate format. It will cause second unnecessary updateFeature on this node to the map.
3419
- if (lon > 180) { lon = 180 - lon; meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: [ lat, lon ] }); }
3420
-
3421
- if ((lat < 90) && (lat > -90) && (lon < 180) && (lon > -180)) { // Check valid lat/lon
3422
- var feature = new ol.Feature({ geometry: new ol.geom.Point(ol.proj.transform([lon, lat], 'EPSG:4326','EPSG:3857')), name: node.name, status: node.conn, lat: lat, lon: lon });
3423
- feature.setId(node._id); // Set id for the device as nodeid
3424
- feature.setStyle(markerStyle(node));
3425
- xxmap.markersSource.addFeature(feature); // Add the feature to Marker Source
3426
- }
3427
- }
3428
- }
3429
-
3430
- // Removing any feature from map
3431
- function removeFeature(node) {
3432
- var feature = xxmap.markersSource.getFeatureById(node._id);
3433
- if (feature) { xxmap.markersSource.removeFeature(feature); }
3434
- }
3435
-
3436
- // Update feature
3437
- function updateFeature(node, feature) {
3438
- if (node.conn != feature.get('status') ) { // Update status if changed
3439
- feature.set('status',node.conn)
3440
- feature.setStyle(markerStyle(node));
3441
- }
3442
-
3443
- // Since this is IP address location, add some fixed randomness to the location. Avoid pin pile-up.
3444
- var loc = map_parseNodeLoc(node);
3445
- if (loc != null) {
3446
- var lat = loc[0], lon = loc[1];
3447
- if ((lat != feature.get('lat')) || (lon != feature.get('lon'))) { // Update lat and lon if changed
3448
- feature.set('lat', lat); feature.set('lon', lon);
3449
- var modifiedCoordinates = ol.proj.transform([parseFloat(lon), parseFloat(lat)], 'EPSG:4326', 'EPSG:3857');
3450
- feature.getGeometry().setCoordinates(modifiedCoordinates);
3451
- }
3452
- }
3453
-
3454
- if (node.name != feature.get('name') ) { feature.set('name', node.name); } // Update name
3455
- }
3456
-
3457
- // Enable dragging of a marker after edit option is clicked in context menu
3458
- function modifyMarkerloc(ft){
3459
- var featid = ft.getId();
3460
- if (featid) {
3461
- ft.setStyle(markerStyle(getNodeFromId(ft.a), 4)); // Switch to a user marker
3462
- if ( !getActiveInteractions(ft)) {
3463
- var dragInteration = new ol.interaction.Modify({
3464
- features: new ol.Collection([ft]),
3465
- pixelTolerance: 10
3466
- });
3467
- xxmap.activeInteractions.push({ featureid: featid, feature:ft, interaction: dragInteration }); // Also keep track of Interactions
3468
- xxmap.map.addInteraction(dragInteration);
3469
- }
3470
- }
3471
- }
3472
-
3473
- // This will be called when save location option is clicked in context menu
3474
- function saveMarkerloc(ft){
3475
- var featid = ft.getId()
3476
- if (featid) {
3477
- var actInteraction = getActiveInteractions(ft);
3478
- if (actInteraction) { // Check if the interaction exists
3479
- xxmap.map.removeInteraction(actInteraction); //Clear Interaction for that node
3480
- removeInteraction(featid);
3481
- var coord = ft.getGeometry().getCoordinates();
3482
- var v = ol.proj.transform(coord, 'EPSG:3857', 'EPSG:4326');
3483
- if (v[0] > 180) { v[0] = 180 - v[0]; }
3484
- var vx = [ v[1], v[0] ]; // Flip the coordinates around, lat/long
3485
- meshserver.send({ action: 'changedevice', nodeid: featid, userloc: vx }); // Send them to server to save changes
3486
- }
3487
- }
3488
- }
3489
-
3490
- // Style the Markers
3491
- function markerStyle(node, type) {
3492
- if (type == null) {
3493
- type = 0;
3494
- if (node.iploc) { type = 1; }
3495
- if (node.wifiloc) { type = 2; }
3496
- if (node.gpsloc) { type = 3; }
3497
- if (node.userloc) { type = 4; }
3498
- }
3499
- var types = ['', '-ip','-wifi','-gps','-user'];
3500
- var color = connStateColor(node);
3501
- var style = new ol.style.Style({
3502
- image: new ol.style.Icon({ color: color, anchor: [0.5, 1], src: 'images/mapmarker' + types[type] + '.png' })
3503
- //stroke: new ol.style.Stroke({ color: '#000', width: 20 })
3504
- //text: new ol.style.Text({ text: 'bob!', textAlign: 'right', offsetX: -10, fill: new ol.style.Fill({ color: '#000' }), stroke: new ol.style.Stroke({ color: '#fff', width: 2 }) })
3505
- });
3506
-
3507
- /*
3508
- deviceMark.setStyle(new ol.style.Style({
3509
- text: new ol.style.Text({
3510
- //font: '12px helvetica,sans-serif',
3511
- text: currentNode.name,
3512
- textAlign: 'right',
3513
- offsetX: -10,
3514
- fill: new ol.style.Fill({ color: '#000' }),
3515
- stroke: new ol.style.Stroke({ color: '#fff', width: 2 })
3516
- }),
3517
- image: new ol.style.Icon(({ color: [113, 140, 0], src: 'images/dot.png' })) }));
3518
- */
3519
-
3520
- return [ style ];
3521
- }
3522
-
3523
- // TODO: Add more connection status types. Currently we only change color if connection status changes
3524
- function connStateColor(nodeConn){
3525
- if (nodeConn.conn == 1 || nodeConn.conn == 3 || nodeConn.conn == 5) { return '#00ffdd'; } // Green for connected devices
3526
- return '#C70039'; // Red if the Agent is not connected
3527
- }
3528
-
3529
- // Add save/edit option to context menu
3530
- function addContextMenuItems(feature) {
3531
- if (getActiveInteractions(feature)) { // If this feature is modified then display save option in contextmenu
3532
- map_cm_saveMarker.data = feature;
3533
- xxmap.contextmenu.push(map_cm_saveMarker);
3534
- } else {
3535
- map_cm_editMarker.data = feature;
3536
- xxmap.contextmenu.push(map_cm_editMarker);
3537
- var node = getNodeFromId(feature.a);
3538
- if (node.userloc) {
3539
- map_cm_clearMarker.data = feature;
3540
- xxmap.contextmenu.push(map_cm_clearMarker);
3541
- }
3542
- }
3543
- map_cm_nodemenu_items.forEach(function (item){
3544
- if (item.text == 'Zoom-in to extent' || item.text == 'Zoom-out to extent') { item.data = feature; }
3545
- else { if (item != "-") { item.data = feature.getId(); } }
3546
- });
3547
- xxmap.contextmenu.extend(map_cm_nodemenu_items);
3548
- }
3549
-
3550
- // Return a active Interaction if it exists in activeInteractions list
3551
- function getActiveInteractions(feature) {
3552
- var featid = feature.getId();
3553
- for (var i = 0; i < xxmap.activeInteractions.length; i++) {
3554
- if (xxmap.activeInteractions[i].featureid == featid) { return xxmap.activeInteractions[i].interaction; }
3555
- }
3556
- return false;
3557
- }
3558
-
3559
- // Return Modified feature based on Id
3560
- function getModifiedFeature(featid) {
3561
- if (featid) {
3562
- for (var i = 0; i < xxmap.activeInteractions.length; i++) {
3563
- if (xxmap.activeInteractions[i].featureid == featid) { return xxmap.activeInteractions[i].feature; }
3564
- }
3565
- }
3566
- return null;
3567
- }
3568
-
3569
- // Remove Interaction
3570
- function removeInteraction(ftid) {
3571
- var index = -1;
3572
- for (var i = 0; i < xxmap.activeInteractions.length; i++) {
3573
- if (xxmap.activeInteractions[i].featureid === ftid) { index = i; break; }
3574
- }
3575
- if (index >= 0) { xxmap.activeInteractions.splice(index, 1); }
3576
- }
3577
-
3578
- // Check if pointer coordinates are equal to features and return node feature
3579
- function getCorrespondingFeature(pointerFeat) {
3580
- var pointerCoord = pointerFeat.getGeometry().getCoordinates();
3581
- for (var i = 0; i < xxmap.activeInteractions.length ; i++) {
3582
- var modifiedFeatures = xxmap.activeInteractions[i].feature;
3583
- var fearCoord = modifiedFeatures.getGeometry().getCoordinates();
3584
- if (fearCoord[0].toFixed(5) == pointerCoord[0].toFixed(5) && fearCoord[1].toFixed(5) == pointerCoord[1].toFixed(5) ) { return modifiedFeatures; }
3585
- }
3586
- return null;
3587
- }
3588
-
3589
- // Refresh the map and clear list
3590
- function refreshMap(reset, rebound){
3591
- if (reset) {
3592
- xxmap.map.setTarget(null);
3593
- xxmap.map = null;
3594
- xxmap.markersSource = null;
3595
- xxmap.mapView = null;
3596
- xxmap.mapLayer = null;
3597
- xxmap.activeInteractions = []; // Clear Active Interaction list
3598
- }
3599
- //clearMeshOptions();
3600
- //onSelectMeshChange();
3601
- var box = updateMapMarkers();
3602
- if ((box != null) && (rebound || (box[4] == 1))) {
3603
- var clat = (box[0] + box[2]) / 2;
3604
- var clon = (box[1] + box[3]) / 2;
3605
- var cscale = Math.max(Math.abs(box[0] - box[2]), Math.abs(box[1] - box[3]));
3606
- var view = xxmap.map.getView();
3607
- view.setCenter(ol.proj.transform([clon, clat], 'EPSG:4326', 'EPSG:3857'));
3608
- var i = 360, j = -2;
3609
- while (i > cscale) { j++; i = i / 2; }
3610
- view.setZoom(j);
3611
- }
3612
- }
3613
-
3614
- // Called When Place a node option is clicked from context menu
3615
- function placeNode(coords) {
3616
- if (xxdialogMode) return;
3617
- var x = '<div style=margin-bottom:6px><label for=selectnode-search>Search</label>  <input type=text placeholder="Device name" id="selectnode-search" onchange=onPlaceNodeInputChange() onkeyup=onPlaceNodeInputChange() autocomplete=off style=width:120px></div><div id=placenode style="height:254px;overflow-y:auto;width:100%;margin:12px 1px 4px 1px;"><div id=noNodesMapPlace style=text-align:center;width:100%;display:none>No devices found.</div>';
3618
- for (var i in nodes) {
3619
- x += '<div class=noselect id=' + nodes[i]._id + '-rowid onclick=selectNodeToPlace(event,\''+ nodes[i]._id +'\') style=background-color:lightgray;margin-bottom:4px;border-radius:2px><input name=PlaceMapDeviceCheckbox id=' + nodes[i]._id + '-checkid type=checkbox style=width:16px;display:inline />';
3620
- x += '<div class=j' + nodes[i].icon + ' style=width:16px;height:16px;margin-top:2px;margin-right:4px;display:inline-block></div><div style=width:16px;display:inline>' + nodes[i].name + '</div></div>';
3621
- }
3622
- setDialogMode(2, "Select a node to place", 3, placeNodeEx, x + '</div>', coords);
3623
- onPlaceNodeInputChange();
3624
- }
3625
-
3626
- function placeNodeEx(button, coords) {
3627
- var elements = document.getElementsByName("PlaceMapDeviceCheckbox");
3628
- for (var i in elements) {
3629
- if (elements[i].checked) {
3630
- var node = getNodeFromId(elements[i].id.substring(0, elements[i].id.length - 8));
3631
- if (node) {
3632
- var feature = xxmap.markersSource.getFeatureById(i);
3633
- var v = ol.proj.transform(coords, 'EPSG:3857', 'EPSG:4326');
3634
- var vx = [ v[1], v[0] ]; // Flip the coordinates around, lat/long
3635
- if (feature) {
3636
- feature.getGeometry().setCoordinates(coords);
3637
- var activeInteraction = getActiveInteractions(feature);
3638
- if (activeInteraction) {
3639
- saveMarkerloc(feature);
3640
- } else { // If this feature is not saved after its location is changed, then send updated coords to server.
3641
- meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: vx }); // Send them to server to save changes
3642
- }
3643
- } else {
3644
- meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: vx }); // This Node is not yet added to maps.
3645
- }
3646
- }
3647
- }
3648
- }
3649
- }
3650
-
3651
- // Called when the user changes the search box
3652
- function onPlaceNodeInputChange() {
3653
- updatePlaceNodeTable(Q('selectnode-search').value.trim().toLowerCase());
3654
- }
3655
-
3656
- // Update the list of devices in the "place on map" table
3657
- function updatePlaceNodeTable(inputSearch) {
3658
- var elements = document.getElementsByName("PlaceMapDeviceCheckbox"), count = 0;
3659
- for (var i in nodes) {
3660
- var visible = ((nodes[i].namel.indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].rnamel != null && nodes[i].rnamel.indexOf(inputSearch) >= 0));
3661
- if (visible) { count++; }
3662
- QV(nodes[i]._id + '-rowid', visible);
3663
- }
3664
- QV('noNodesMapPlace', count == 0);
3665
- /*
3666
- console.log(selected);
3667
- for (var i in nodes) {
3668
- if ((nodes[i].name.toLowerCase().indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].rnamel != null && nodes[i].rnamel.toLowerCase().indexOf(inputSearch) >= 0)) {
3669
- console.log(selected.indexOf(nodes[i]._id));
3670
- x += '<div class=noselect id=' + nodes[i]._id + '-rowid onclick=selectNodeToPlace(event,\''+ nodes[i]._id +'\') style=background-color:lightgray;margin-bottom:4px;border-radius:2px><input name=PlaceMapDeviceCheckbox id=' + nodes[i]._id + '-checkid type=checkbox style=width:16px;display:inline ' + ((selected.indexOf(nodes[i]._id) >= 0)?'checked':'') + ' />';
3671
- x += '<div class=j' + nodes[i].icon + ' style=width:16px;height:16px;margin-top:2px;margin-right:4px;display:inline-block></div><div style=width:16px;display:inline>' + nodes[i].name + '</div></div>';
3672
- }
3673
- }
3674
- if (x == '') { x = '<div style=text-align:center;width:100%>No devices found.</div>'; }
3675
- QH('placenode', '');
3676
- */
3677
- }
3678
-
3679
- // Called when a user clicks on a device to toggle selection for placement on map.
3680
- function selectNodeToPlace(e, id) {
3681
- // Toggle checkbox if needed
3682
- if (e.target.name != 'PlaceMapDeviceCheckbox') { var inputElement = Q(id + '-checkid'); inputElement.checked = !inputElement.checked; }
3683
-
3684
- // Check button state
3685
- var elements = document.getElementsByName("PlaceMapDeviceCheckbox"), checkcount = 0;
3686
- for (var i in elements) { if (elements[i].checked) checkcount++; }
3687
- QE('idx_dlgOkButton', checkcount > 0);
3688
- }
3689
-
3690
- // Add option for available meshes in mesh Dropdown
3691
- function addMeshOptions(addMeshid, meshName) {
3692
- /*
3693
- var meshOptions = Q('select-mesh');
3694
- if (addMeshid && meshName) {
3695
- var option = document.createElement('option');
3696
- option.value =addMeshid;
3697
- option.text = meshName;
3698
- meshOptions.add(option); // Add specific option
3699
- }
3700
- else {
3701
- for (var i in meshes) { // Add all options
3702
- var option = document.createElement('option');
3703
- option.value = i;
3704
- option.text = meshes[i].name;
3705
- meshOptions.add(option);
3706
- }
3707
- }
3708
- */
3709
- }
3710
-
3711
- // Remove/Modify options in Mesh dropdown (if modMeshname is defined then Modify else Remove)
3712
- function meshOptionRmvMod(delMeshid, modMeshname){
3713
- /*
3714
- var meshOptions = Q('select-mesh');
3715
- if (delMeshid) {
3716
- var index=-1;
3717
- for (var i = 1; i < meshOptions.options.length; i++) {
3718
- if (meshOptions[i].value === delMeshid) { index=i; }
3719
- }
3720
- if (index > 0) {
3721
- if (modMeshname) {
3722
- meshOptions[index].innerHTML=modMeshname; // If Mesh name is Modified
3723
- }
3724
- else { meshOptions.remove(index); }
3725
- }
3726
- }
3727
- */
3728
- }
3729
-
3730
- //Check if there is any mesh created
3731
- function meshExists() {
3732
- for (var i in meshes) { if (meshes[i]) { return true; } }
3733
- return false;
3734
- }
3735
-
3736
- // Reset Mesh dropdown option to 'All' when a current view mesh is deleted.
3737
- function setMeshView(emeshid) {
3738
- var selectMeshElement=Q("select-mesh");
3739
- var selectedIndex = selectMeshElement.selectedIndex;
3740
- if (selectMeshElement[selectedIndex].value == emeshid) { selectMeshElement[0].selected = true; onSelectMeshChange(); }
3741
- }
3742
-
3743
- // Clear all mesh options except 'All'
3744
- function clearMeshOptions() {
3745
- /*
3746
- var meshOptions=Q('select-mesh');
3747
- for(var i = meshOptions.options.length - 1 ; i > 0 ; i--) { meshOptions.remove(i); }
3748
- */
3749
- }
3750
-
3751
- // Make a http get call- Replace this with AJAX get if jquery is used
3752
- function getSearchLocation() {
3753
- try {
3754
- var searchdata = Q('mapSearchLocation').value.trim();
3755
- if (searchdata.length > 0) {
3756
- var xmlhttp = new XMLHttpRequest(); // Compatible with Chrome, Opera, Safari, IE7+, Firefox.
3757
- xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { formatSearchData(xmlhttp.responseText); } }
3758
- xmlhttp.open("GET", 'https://nominatim.openstreetmap.org/search?q=' + searchdata + '&format=json', true); // Get request
3759
- xmlhttp.send();
3760
- }
3761
- } catch (e) {}
3762
- }
3763
-
3764
- // Format data recieved from nominatim API and display it on content window
3765
- function formatSearchData(data) {
3766
- try {
3767
- QH('xmapSearchResults','');
3768
- var dataInfo = JSON.parse(data), count = 0, x = '<div class="xmapItem">';
3769
- for (var i = 0; i < dataInfo.length; i++) {
3770
- if (dataInfo[i].display_name && dataInfo[i].boundingbox[0] && dataInfo[i].boundingbox[1] && dataInfo[i].boundingbox[2] && dataInfo[i].boundingbox[3]) {
3771
- count++;
3772
- var itemclass = (i % 2 == 0)?'xmapItemSel1':'xmapItemSel1';
3773
- x += '<div class="' + itemclass + '" onclick=mapGotoSelectedLocation(this)><div>' + dataInfo[i].display_name + '</div><div style=display:none>' + dataInfo[i].boundingbox[0] + '!#!' + dataInfo[i].boundingbox[1] + '!#!' + dataInfo[i].boundingbox[2] + '!#!' + dataInfo[i].boundingbox[3] + '</div></div>';
3774
- }
3775
- }
3776
- x += '</div>';
3777
- if (count == 1) {
3778
- // If only one result is returned then zoom to that location
3779
- var extent = [ parseFloat(dataInfo[0].boundingbox[2]), parseFloat(dataInfo[0].boundingbox[0]), parseFloat(dataInfo[0].boundingbox[3]), parseFloat(dataInfo[0].boundingbox[1]) ];
3780
- zoomToExtent(extent);
3781
- } else {
3782
- if (count == 0) { x = '<div style=width:200px>No location found.<div>'; }
3783
- QV('xmapSearchResultsDlg', true);
3784
- }
3785
- QH('xmapSearchResults', x);
3786
- }
3787
- catch (e) {}
3788
- }
3789
-
3790
- // Zoom into the bounding box
3791
- function mapGotoSelectedLocation(obj) {
3792
- var objchildren = obj.children;
3793
- var boundingBox = objchildren[1].innerHTML.split('!#!');
3794
- var extent = [parseFloat(boundingBox[2]), parseFloat(boundingBox[0]), parseFloat(boundingBox[3]), parseFloat(boundingBox[1])];
3795
- //Q('search-location').value = objchildren[0].innerHTML;
3796
- zoomToExtent(extent);
3797
- mapCloseSearchWindow();
3798
- }
3799
-
3800
- // Close the search window
3801
- function mapCloseSearchWindow() {
3802
- QH('xmapSearchResults', '');
3803
- QV('xmapSearchResultsDlg', false);
3804
- }
3805
-
3806
- // Zoom to specific cordinates
3807
- function zoomToLocation(coordinates, zoomVal) {
3808
- var view = xxmap.map.getView();
3809
- view.setCenter(coordinates);
3810
- view.setZoom(zoomVal);
3811
- }
3812
-
3813
- function zoomToFitExtent() {
3814
- var features = xxmap.markersSource.getFeatures();
3815
- if (features.length > 0) {
3816
- var extent = xxmap.markersSource.getExtent();
3817
- xxmap.map.getView().fit(extent, xxmap.map.getSize());
3818
- }
3819
- }
3820
-
3821
- function zoomToExtent(extent){
3822
- var boundingExtent = ol.proj.transformExtent(extent, ol.proj.get('EPSG:4326'), ol.proj.get('EPSG:3857'));
3823
- xxmap.map.getView().fit(boundingExtent, xxmap.map.getSize());
3824
- }
3825
-
3826
-
3827
- //
3828
- // MY DEVICE
3829
- //
3830
- function refreshDevice(nodeid) {
3831
- if (!currentNode || currentNode._id != nodeid) return;
3832
- gotoDevice(nodeid, xxcurrentView, true);
3833
- }
3834
-
3835
- function getNodeRights(nodeid) {
3836
- var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
3837
- return mesh.links[userinfo._id].rights;
3838
- }
3839
-
3840
- var currentNode;
3841
- var powerTimelineNode = null;
3842
- var powerTimelineReq = null;
3843
- var powerTimelineUpdate = null;
3844
- var powerTimeline = null;
3845
- function getCurrentNode() { return currentNode; };
3846
- function gotoDevice(nodeid, panel, refresh, event) {
3847
- // Remind the user to verify the email address
3848
- if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return; }
3849
-
3850
- // Remind the user to add two factor authentication
3851
- if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0))) { setDialogMode(2, "Account Security", 1, null, "Unable to access a device until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return; }
3852
-
3853
- if (event && (event.shiftKey == true)) {
3854
- // Open the device in a different tab
3855
- window.open(window.location.origin + '?node=' + nodeid.split('/')[2] + '&viewmode=10&hide=16', 'meshcentral:' + nodeid);
3856
- return;
3857
- }
3858
-
3859
- //disconnectAllKvmFunction();
3860
- var node = getNodeFromId(nodeid);
3861
- var mesh = meshes[node.meshid];
3862
- var meshrights = mesh.links[userinfo._id].rights;
3863
- if (!currentNode || currentNode._id != node._id || refresh == true) {
3864
- currentNode = node;
3865
-
3866
- // Add node name
3867
- var nname = EscapeHtml(node.name);
3868
- if (nname.length == 0) { nname = '<i>None</i>'; }
3869
- if (((meshrights & 4) != 0) && ((!mesh.flags) || ((mesh.flags & 2) == 0))) { nname = '<span tabindex=0 title="Click here to edit the server-side device name" onclick=showEditNodeValueDialog(0) onkeyup="if (event.key == \'Enter\') showEditNodeValueDialog(0)" style=cursor:pointer>' + nname + ' <img class=hoverButton src="images/link5.png" /></span>'; }
3870
- QH('p10deviceName', nname);
3871
- QH('p11deviceName', nname);
3872
- QH('p12deviceName', nname);
3873
- QH('p13deviceName', nname);
3874
- QH('p14deviceName', nname);
3875
- QH('p15deviceName', 'Console - ' + nname);
3876
- QH('p16deviceName', nname);
3877
-
3878
- // Node attributes
3879
- var x = '<table style=width:100%>';
3880
-
3881
- // Attribute: Mesh
3882
- x += addDeviceAttribute('<span title="The name of the device group this computer belong to.">Group</span>', '<a href=# title="The name of the device group this computer belong to" onclick=gotoMesh("' + node.meshid + '") style=cursor:pointer>' + EscapeHtml(meshes[node.meshid].name) + '</a>');
3883
-
3884
- // Attribute: Name
3885
- if ((node.rname != null) && (node.name != node.rname)) { x += addDeviceAttribute('<span title="The name of this computer as set in the operating system">Name</span>', '<span title="The name of this computer as set in the operating system">' + EscapeHtml(node.rname) + '</span>'); }
3886
-
3887
- // Attribute: Host
3888
- if ((features & 1) == 0) { // If not WAN-only, local hostname is in use
3889
- if ((meshrights & 4) != 0) {
3890
- if (node.host) {
3891
- x += addDeviceAttribute('Hostname', '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer>' + EscapeHtml(node.host) + '</span>');
3892
- } else {
3893
- x += addDeviceAttribute('Hostname', '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer><i>None</i></span>');
3894
- }
3895
- } else {
3896
- x += addDeviceAttribute('Hostname', EscapeHtml(node.host));
3897
- }
3898
- }
3899
-
3900
- // Attribute: Description
3901
- var description = node.desc?EscapeHtml(node.desc):"<i>None</i>";
3902
- if ((meshrights & 4) != 0) {
3903
- x += addDeviceAttribute('Description', '<span onclick=showEditNodeValueDialog(2) style=cursor:pointer>' + description + ' <img class=hoverButton src="images/link5.png" /></span>');
3904
- } else {
3905
- x += addDeviceAttribute('Description', description);
3906
- }
3907
-
3908
- // Attribute: Mesh Agent
3909
- var agentsStr = ['Unknown', 'Windows 32bit console', 'Windows 64bit console', 'Windows 32bit service', 'Windows 64bit service', 'Linux 32bit', 'Linux 64bit', 'MIPS', 'XENx86', 'Android ARM', 'Linux ARM', 'MacOS 32bit', 'Android x86', 'PogoPlug ARM', 'Android APK', 'Linux Poky x86-32bit', 'MacOS 64bit', 'ChromeOS', 'Linux Poky x86-64bit', 'Linux NoKVM x86-32bit', 'Linux NoKVM x86-64bit', 'Windows MinCore console', 'Windows MinCore service', 'NodeJS', 'ARM-Linaro', 'ARMv6l / ARMv7l', 'ARMv8 64bit', 'ARMv6l / ARMv7l / NoKVM', 'Unknown', 'Unknown', 'FreeBSD x86-64'];
3910
- if ((node.agent != null) && (node.agent.id != null) && (node.agent.ver != null)) {
3911
- var str = '';
3912
- if (node.agent.id <= agentsStr.length) { str = agentsStr[node.agent.id]; } else { str = agentsStr[0]; }
3913
- if (node.agent.ver != 0) { str += ' v' + node.agent.ver; }
3914
- x += addDeviceAttribute('Mesh Agent', str);
3915
- }
3916
-
3917
- // Attribute: Intel AMT
3918
- if (node.intelamt != null) {
3919
- var str = '';
3920
- var provisioningStates = { 0: 'Not Activated (Pre)', 1: 'Not Activated (In)', 2: 'Activated' };
3921
- if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>Unknown State</i>, v' + node.intelamt.ver; } else
3922
-
3923
- if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '<i>Activated</i>'; }
3924
- else if ((node.intelamt.ver == null) || (node.intelamt.state == null)) { str += '<i>Unknown Version & State</i>'; }
3925
- else {
3926
- str += provisioningStates[node.intelamt.state];
3927
- if ((node.intelamt.state == 2) && node.intelamt.flags) { if (node.intelamt.flags & 2) { str += ' <span title="Intel AMT is activated in Client Control Mode">CCM</span>'; } else if (node.intelamt.flags & 4) { str += ' <span title="Intel AMT is activated in Admin Control Mode">ACM</span>'; } }
3928
- str += (', v' + node.intelamt.ver);
3929
- }
3930
-
3931
- if (node.intelamt.tls == 1) { str += ', <span title="Intel AMT is setup with TLS network security">TLS</span>'; }
3932
- if (node.intelamt.state == 2) {
3933
- if (node.intelamt.user == null || node.intelamt.user == '') {
3934
- if ((meshrights & 4) != 0) {
3935
- str += ', <i style=color:#FF0000;cursor:pointer title="Edit Intel® AMT credentials" onclick=editDeviceAmtSettings("' + node._id + '")>No Credentials</i>';
3936
- } else {
3937
- str += ', <i style=color:#FF0000>No Credentials</i>';
3938
- }
3939
- }
3940
- str += ' ';
3941
- if ((meshrights & 4) != 0) {
3942
- str += '<img src=images/link4.png height=10 width=10 title="Edit Intel® AMT credentials" style=cursor:pointer onclick=editDeviceAmtSettings("' + node._id + '")>';
3943
- }
3944
- }
3945
- x += addDeviceAttribute('Intel® AMT', str);
3946
- }
3947
-
3948
- if (mesh.mtype == 2) {
3949
- // Attribute: Mesh Agent Tag
3950
- if ((node.agent != null) && (node.agent.tag != null)) {
3951
- var tag = EscapeHtml(node.agent.tag);
3952
- if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
3953
- x += addDeviceAttribute('Agent Tag', tag);
3954
- }
3955
- } else {
3956
- // Attribute: Intel AMT Tag
3957
- if ((node.intelamt != null) && (node.intelamt.tag != null)) {
3958
- var tag = EscapeHtml(node.intelamt.tag);
3959
- if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
3960
- x += addDeviceAttribute('Intel® AMT Tag', tag);
3961
- }
3962
- }
3963
-
3964
- // Attribute: Intel AMT
3965
- //if (node.intelamt && node.intelamt.user) { x += addDeviceAttribute('Intel® AMT', node.intelamt.user); }
3966
-
3967
- // Operating system description
3968
- if (node.osdesc) { x += addDeviceAttribute('Operating System', node.osdesc); }
3969
-
3970
- // Active Users
3971
- if (node.users && node.conn && (node.users.length > 0) && (node.conn & 1)) { x += addDeviceAttribute('Active User' + ((node.users.length > 1)?'s':''), node.users.join(', ')); }
3972
-
3973
- // Attribute: Connectivity (Only show this if more than just the agent is connected).
3974
- var connectivity = node.conn;
3975
- if (connectivity && connectivity > 1) {
3976
- var cstate = [];
3977
- if ((node.conn & 1) != 0) cstate.push('<span title="Mesh agent is connected and ready for use.">Mesh Agent</span>');
3978
- if ((node.conn & 2) != 0) cstate.push('<span title="Intel® AMT CIRA is connected and ready for use.">Intel® AMT CIRA</span>');
3979
- else if ((node.conn & 4) != 0) cstate.push('<span title="Intel® AMT is routable and ready for use.">Intel® AMT</span>');
3980
- if ((node.conn & 8) != 0) cstate.push('<span title="Mesh agent is reachable using another agent as relay.">Mesh Relay</span>');
3981
- x += addDeviceAttribute('Connectivity', cstate.join(', '));
3982
- }
3983
-
3984
- // Node grouping tags
3985
- var groupingTags = '<i>None</i>';
3986
- if (node.tags != null) { groupingTags = ''; for (var i in node.tags) { groupingTags += '<span class="tagSpan">' + node.tags[i] + '</span>'; } }
3987
- if ((meshrights & 4) != 0) {
3988
- x += addDeviceAttribute('Tags', '<span onclick=showEditNodeValueDialog(3) style=cursor:pointer>' + groupingTags + ' <img class=hoverButton src="images/link5.png" /></span>');
3989
- } else {
3990
- x += addDeviceAttribute('Tags', groupingTags);
3991
- }
3992
-
3993
- x += '</table><br />';
3994
- // Show action button, only show if we have permissions 4, 8, 64
3995
- if ((meshrights & 76) != 0) { x += '<input type=button value=Actions title="Perform power actions on the device" onclick=deviceActionFunction() />'; }
3996
- x += '<input type=button value=Notes title="View notes about this device" onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
3997
- //if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += '<input type=button value=Toast title="Display a text message of the remote device" onclick=deviceToastFunction() />'; }
3998
- QH('p10html', x);
3999
-
4000
- // Show node last 7 days timeline
4001
- masterUpdate(256);
4002
-
4003
- // Show bottom buttons
4004
- x = '<div class="p10html3right">';
4005
- if ((meshrights & 4) != 0) {
4006
- // TODO: Show change group only if there is another mesh of the same type.
4007
- x += ' <a href=# onclick=p10showChangeGroupDialog(["' + node._id + '"]) title="Move this device to a different device group">Change Group</a>';
4008
- x += ' <a href=# onclick=p10showDeleteNodeDialog("' + node._id + '") title="Remove this device">Delete Device</a>';
4009
- }
4010
- x += '</div><div class="p10html3left">';
4011
- if (mesh.mtype == 2) x += '<a href=# onclick=p10showNodeNetInfoDialog("' + node._id + '") title="Show device network interface information">Interfaces</a> ';
4012
- if (xxmap != null) x += '<a href=# onclick=p10showNodeLocationDialog("' + node._id + '") title="Show device locations information">Location</a> ';
4013
- if (((meshrights & 8) != 0) && (mesh.mtype == 2)) x += '<a href=# onclick=p10showMeshCmdDialog(1,"' + node._id + '") title="Traffic router used to connect to a device thru this server.">Router</a> ';
4014
-
4015
- // RDP link, show this link only of the remote machine is Windows.
4016
- if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0)) {
4017
- if ((node.agent.id > 0) && (node.agent.id < 5)) { x += '<a href=# onclick=p10clickOnce("' + node._id + '","RDP2",3389) title="Requires Microsoft ClickOnce support in your browser.">RDP</a> '; }
4018
- if (node.agent.id > 4) {
4019
- x += '<a href=# onclick=p10clickOnce("' + node._id + '","PSSH",22) title="Requires Microsoft ClickOnce support in your browser.">Putty</a> ';
4020
- x += '<a href=# onclick=p10clickOnce("' + node._id + '","WSCP",22) title="Requires Microsoft ClickOnce support in your browser.">WinSCP</a> ';
4021
- }
4022
- }
4023
- x += '</div><br>'
4024
-
4025
- QH('p10html3', x);
4026
-
4027
- // Set the node power state
4028
- var powerstate = PowerStateStr(node.state);
4029
- //if (node.state == 0) { powerstate = 'Unknown State'; }
4030
- if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Agent connected">Agent connected</span>'; }
4031
- if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Intel® AMT connected">Intel® AMT connected</span>'; }
4032
- else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Intel® AMT detected">Intel® AMT detected</span>'; }
4033
- if ((powerstate == '') && node.lastconnect) { powerstate = '<span style=font-size:12px>Last seen:<br />' + printDateTime(new Date(node.lastconnect)) + '</span>'; }
4034
- QH('MainComputerState', powerstate);
4035
-
4036
- // Set the node icon
4037
- Q('MainComputerImage').setAttribute("src", "images/icons256-" + node.icon + "-1.png");
4038
- Q('MainComputerImage').className = ((!node.conn) || (node.conn == 0)?'gray':'');
4039
-
4040
- // Check if we have terminal and file access
4041
- var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0));
4042
- var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0));
4043
- var amtAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 2048) == 0));
4044
-
4045
- // Setup/Refresh the desktop tab
4046
- if (terminalAccess) { setupTerminal(); }
4047
- if (fileAccess) { setupFiles(); }
4048
- var consoleRights = ((meshrights & 16) != 0);
4049
- if (consoleRights) { setupConsole(); } else { if (panel == 15) { panel = 10; } }
4050
-
4051
- // Show or hide the tabs
4052
- // mesh.mtype: 1 = Intel AMT only, 2 = Mesh Agent
4053
- // node.agent.caps (bitmask): 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console
4054
- QV('MainDevDesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((meshrights & 8) || (meshrights & 256)));
4055
- QV('MainDevTerminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8) && terminalAccess);
4056
- QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess);
4057
- QV('MainDevAmt', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8) && amtAccess);
4058
- QV('MainDevConsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
4059
- QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0));
4060
- QH('p15coreName', ((node.agent != null) && (node.agent.core != null))?node.agent.core:'');
4061
-
4062
- // Setup/Refresh Intel AMT tab
4063
- var amtFrameNode = Q('p14iframe').contentWindow.getCurrentMeshNode();
4064
- if ((amtFrameNode != null) && (amtFrameNode._id != currentNode._id)) { Q('p14iframe').contentWindow.disconnect(); }
4065
- var online = ((node.conn & 6) != 0)?true:false; // If CIRA (2) or AMT (4) connected, enable Commander
4066
- Q('p14iframe').contentWindow.setConnectionState(online);
4067
- Q('p14iframe').contentWindow.setFrameHeight('650px');
4068
- Q('p14iframe').contentWindow.setAuthCallback(updateAmtCredentials);
4069
-
4070
- // Display "action" button on desktop/terminal/files
4071
- QV('deskActionsBtn', (meshrights & 72) != 0); // 72 = Wake-up + Remote Control permissions
4072
- QV('termActionsBtn', (meshrights & 72) != 0);
4073
- QV('filesActionsBtn', (meshrights & 72) != 0);
4074
-
4075
- // Request the power timeline
4076
- if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) {
4077
- QH('p10html2', '');
4078
- powerTimelineReq = currentNode._id;
4079
- meshserver.send({ action: 'powertimeline', nodeid: currentNode._id });
4080
- meshserver.send({ action: 'lastconnect', nodeid: currentNode._id });
4081
- }
4082
-
4083
- // Reset the desktop tools
4084
- QV('DeskTools', false);
4085
- showDeskToolsProcesses();
4086
-
4087
- // Ask for device events
4088
- refreshDeviceEvents();
4089
-
4090
- // Update the web page title
4091
- if ((currentNode) && (xxcurrentView >= 10) && (xxcurrentView < 20)) { document.title = decodeURIComponent("{{{extitle}}}") + ' - ' + currentNode.name; } else { document.title = decodeURIComponent("{{{extitle}}}"); }
4092
-
4093
- // Clear user consent status if present
4094
- p11clearConsoleMsg();
4095
- p12clearConsoleMsg();
4096
- p13clearConsoleMsg();
4097
- }
4098
- setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
4099
- if (!panel) panel = 10;
4100
- go(panel);
4101
- }
4102
-
4103
- function showNotes(readonly, noteid) {
4104
- if (xxdialogMode) return;
4105
- setDialogMode(2, "Notes", 2, showNotesEx, '<textarea id=d2devNotes ro=' + readonly + ' noteid=' + noteid + ' readonly style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea><span style=font-size:10px>Device group notes can be viewed and changed by other device group administrators.<span>', noteid);
4106
- meshserver.send({ action: 'getNotes', id: decodeURIComponent(noteid) });
4107
- }
4108
-
4109
- function showNotesEx(buttons, tag) { meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponent(Q('d2devNotes').value) }); }
4110
-
4111
- function deviceChat() {
4112
- if (xxdialogMode) return;
4113
- var url = '/messenger?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name;
4114
- if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
4115
- window.open(url, 'meshmessenger:' + currentNode._id);
4116
- meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
4117
- }
4118
-
4119
- function deviceUrlFunction() {
4120
- if (xxdialogMode) return;
4121
- setDialogMode(2, "Open Page on Device", 3, deviceUrlFunctionEx, '<input id=d2devurl placeholder="http://server.com" style=width:100%;overflow-y:scroll></input>');
4122
- }
4123
-
4124
- function deviceUrlFunctionEx() {
4125
- meshserver.send({ action: 'msg', type: 'openUrl', nodeid: currentNode._id, url: Q('d2devurl').value });
4126
- }
4127
-
4128
- function deviceToastFunction() {
4129
- if (xxdialogMode) return;
4130
- setDialogMode(2, "Device Notification", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
4131
- }
4132
-
4133
- function deviceToastFunctionEx() {
4134
- meshserver.send({ action: 'toast', nodeids: [ currentNode._id ], title: 'MeshCentral', msg: Q('d2devToast').value });
4135
- }
4136
-
4137
- function deviceActionFunction() {
4138
- if (xxdialogMode) return;
4139
- var meshrights = meshes[currentNode.meshid].links[userinfo._id].rights;
4140
- var x = "Select an operation to perform on this device.<br /><br />";
4141
- var y = '<select id=d2deviceop style=float:right;width:250px>';
4142
- if ((meshrights & 64) != 0) { y += '<option value=100>Wake-up</option>'; } // Wake-up permission
4143
- if ((meshrights & 8) != 0) { y += '<option value=4>Sleep</option><option value=3>Reset</option><option value=2>Power off</option>'; } // Remote control permission
4144
- y += '</select>';
4145
- x += addHtmlValue('Operation', y);
4146
- setDialogMode(2, "Device Action", 3, deviceActionFunctionEx, x);
4147
- }
4148
-
4149
- function deviceActionFunctionEx() {
4150
- var op = Q('d2deviceop').value;
4151
- if (op == 100) {
4152
- // Device wake
4153
- meshserver.send({ action: 'wakedevices', nodeids: [ currentNode._id ] });
4154
- } else {
4155
- // Power operation
4156
- meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: op });
4157
- }
4158
- }
4159
-
4160
- // Called when MeshCommander needs new credentials or updated credentials.
4161
- function updateAmtCredentials(forceDialog) {
4162
- var node = getNodeFromId(currentNode._id);
4163
- if ((forceDialog == true) || (node.intelamt.user == null) || (node.intelamt.user == '')) {
4164
- editDeviceAmtSettings(currentNode._id, updateAmtCredentialsEx);
4165
- } else {
4166
- Q('p14iframe').contentWindow.connectButtonfunctionEx();
4167
- }
4168
- }
4169
-
4170
- function updateAmtCredentialsEx(button, tag) {
4171
- Q('p14iframe').contentWindow.connectButtonfunctionEx();
4172
- }
4173
-
4174
- // Look to see if we need to update the device timeline
4175
- function updateDeviceTimeline() {
4176
- if ((meshserver.State != 2) || (powerTimelineNode == null) || (powerTimelineUpdate == null) || (currentNode == null)) return;
4177
- if ((powerTimelineNode == powerTimelineReq) && (currentNode._id == powerTimelineNode) && (powerTimelineUpdate < Date.now())) {
4178
- powerTimelineUpdate = null;
4179
- meshserver.send({ action: 'powertimeline', nodeid: currentNode._id });
4180
- meshserver.send({ action: 'lastconnect', nodeid: currentNode._id });
4181
- }
4182
- }
4183
-
4184
- // Draw device power bars. The bars are 766px wide.
4185
- function drawDeviceTimeline() {
4186
- if ((currentNode == null) || (xxcurrentView < 10) || (xxcurrentView > 19)) return;
4187
- var timeline = null, now = Date.now();
4188
- if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
4189
-
4190
- // Calculate when the timeline starts
4191
- var d = new Date();
4192
- d.setHours(0, 0, 0, 0);
4193
- d = new Date(d.getTime() - (1000 * 60 * 60 * 24 * 6));
4194
- var timelineStart = d.getTime();
4195
-
4196
- // De-compact the timeline
4197
- var timeline2 = [];
4198
- if (timeline != null && timeline.length > 1) {
4199
- timeline2.push([ 0, timeline[1], timeline[0] ]); // Start, End, Power
4200
- var ct = timeline[1];
4201
- for (var i = 2; i < timeline.length; i += 2) {
4202
- var power = timeline[i], dt = now;
4203
- if (timeline.length > (i + 1)) { dt = timeline[i + 1]; }
4204
- timeline2.push([ ct, ct + dt, power ]); // Start, End, Power
4205
- ct = ct + dt;
4206
- }
4207
- }
4208
-
4209
- // Draw the timeline
4210
- var x = '', count = 1, date = new Date();
4211
- var totalWidth = Q('masthead').offsetWidth - (160 + 9 + 9 + 14); // Compute the total width of the power bar
4212
- date.setHours(0, 0, 0, 0);
4213
- for (var i = 0; i < 7; i++) {
4214
- var datavalue = '', start = date.getTime(), end = start + (1000 * 60 * 60 * 24);
4215
- for (var j in timeline2) {
4216
- var block = timeline2[j];
4217
- if (isTimeBlockInside(start, end, block[0], block[1]) == true) {
4218
- var ts = Math.max(start, block[0]);
4219
- var te = Math.min(Math.min(end, block[1]), now);
4220
- var width = Math.round(((te - ts) * totalWidth) / 86400000);
4221
- if (width > 0) {
4222
- var title = powerStateStrings2[block[2]] + ' from ' + printTime(new Date(ts)) + ' to ' + printTime(new Date(te)) + '.';
4223
- datavalue += '<div class="pwState ' + powerColor(block[2]) + '" title="' + title + '" style="width:' + width + 'px;"></div>';
4224
- }
4225
- }
4226
- }
4227
- x += '<tr class=' + (((count % 2) == 0)?'altBack':'') + '><td><div> ' + printDate(date) + '<div></div></div></td><td><div>' + datavalue + '</div></td></tr>';
4228
- ++count;
4229
- date = new Date(date.getTime() - (1000 * 60 * 60 * 24)); // Substract one day
4230
- }
4231
- QH('p10html2', '<table cellpadding=2 cellspacing=0><thead><tr style=><th scope=col style=text-align:center;width:150px>Day</th><th scope=col style=text-align:center><a download href="devicepowerevents.ashx?id=' + currentNode._id + '" onclick="setDialogMode(0)"><img title="Download power events" src="images/link4.png" /></a>7 Day Power State</th></tr></thead><tbody>' + x + '</tbody></table>');
4232
- }
4233
-
4234
- // Return a color for the given power state
4235
- function powerColor(x) { if (x < powerColorTable.length) { return powerColorTable[x]; } return 'pwsYellow'; }
4236
-
4237
- // Return true if the time block is visible within the start/end period
4238
- function isTimeBlockInside(start, end, blockStart, blockEnd) {
4239
- if ((blockStart < start) && (blockEnd > end)) return true; // Block is wider than timespan
4240
- if ((blockStart > start) && (blockStart < end)) return true;
4241
- if ((blockEnd > start) && (blockEnd < end)) return true;
4242
- return false;
4243
- }
4244
-
4245
- function addDeviceAttribute(name, value) { return '<tr><td class=style7>' + name + '</td><td class=style9>' + value + '</td></tr>'; }
4246
-
4247
- function editDeviceAmtSettings(nodeid, func, arg) {
4248
- if (xxdialogMode) return;
4249
- var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
4250
- if ((meshrights & 4) == 0) return;
4251
- x += addHtmlValue('Username', '<input id=dp10username style=width:230px maxlength=32 autocomplete=nope placeholder="admin" onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
4252
- x += addHtmlValue('Password', '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
4253
- x += addHtmlValue('Security', '<select id=dp10tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
4254
- if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
4255
- setDialogMode(2, "Edit Intel® AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func, arg: arg });
4256
- if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
4257
- Q('dp10tls').value = node.intelamt.tls;
4258
- validateDeviceAmtSettings();
4259
- }
4260
-
4261
- function validateDeviceAmtSettings() {
4262
- QE('idx_dlgOkButton', passwordcheck(Q('dp10password').value));
4263
- }
4264
-
4265
- function editDeviceAmtSettingsEx(button, tag) {
4266
- if (button == 2) {
4267
- // Delete button pressed, remove credentials
4268
- meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: '', pass: '' } });
4269
- } else {
4270
- // Change Intel AMT credentials
4271
- var amtuser = Q('dp10username').value;
4272
- if (amtuser == '') amtuser = 'admin';
4273
- var amtpass = Q('dp10password').value;
4274
- if (amtpass == '') amtuser = '';
4275
- meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
4276
- tag.node.intelamt.user = amtuser;
4277
- tag.node.intelamt.tls = Q('dp10tls').value;
4278
- if (tag.func) { setTimeout(function () { tag.func(null, tag.arg); }, 300); }
4279
- }
4280
- }
4281
-
4282
- function p10showChangeGroupDialog(nodeids) {
4283
- if (xxdialogMode) return false;
4284
- var targetMeshId = null;
4285
- if (nodeids.length == 1) { try { targetMeshId = meshes[getNodeFromId(nodeids[0])]._id; } catch (ex) { } }
4286
-
4287
- // List all available alternative groups
4288
- var y = "<select id=p10newGroup style=width:236px>", count = 0;
4289
- for (var i in meshes) {
4290
- var meshrights = meshes[i].links[userinfo._id].rights;
4291
- if ((meshes[i]._id != targetMeshId) && (meshrights & 4)) { count++; y += "<option value='" + meshes[i]._id + "'>" + meshes[i].name + "</option>"; }
4292
- }
4293
- y += "</select>";
4294
-
4295
- if (count > 0) {
4296
- var x = (nodeids.length == 1) ? "Select a new group for this device<br /><br />" : "Select a new group for selected devices<br /><br />";
4297
- x += addHtmlValue('New Device Group', y);
4298
- setDialogMode(2, "Change Group", 3, p10showChangeGroupDialogEx, x, nodeids);
4299
- } else {
4300
- setDialogMode(2, "Change Group", 1, null, "No other device group of same type exists.");
4301
- }
4302
- return false;
4303
- }
4304
-
4305
- function p10showChangeGroupDialogEx(b, nodeids) {
4306
- meshserver.send({ action: 'changeDeviceMesh', nodeids: nodeids, meshid: Q('p10newGroup').value });
4307
- }
4308
-
4309
- function p10showDeleteNodeDialog(nodeid) {
4310
- if (xxdialogMode) return false;
4311
- var x = "Are you sure you want to delete node \"" + EscapeHtml(currentNode.name) + "\"?<br /><br />";
4312
- x += "<label><input id=p10check type=checkbox onchange=p10validateDeleteNodeDialog() />Confirm</label>";
4313
- setDialogMode(2, "Delete Node", 3, p10showDeleteNodeDialogEx, x, nodeid);
4314
- p10validateDeleteNodeDialog();
4315
- return false;
4316
- }
4317
-
4318
- function p10validateDeleteNodeDialog() {
4319
- QE('idx_dlgOkButton', Q('p10check').checked);
4320
- }
4321
-
4322
- function p10showDeleteNodeDialogEx(buttons, nodeid) {
4323
- meshserver.send({ action: 'removedevices', nodeids: [ nodeid ] });
4324
- }
4325
-
4326
- function p10clickOnce(nodeid, protocol, port) {
4327
- meshserver.send({ action: 'getcookie', nodeid: nodeid, tcpport: port, tag: 'clickonce', protocol: protocol });
4328
- return false;
4329
- }
4330
-
4331
- // Show current location
4332
- var d2map = null;
4333
- function p10showNodeLocationDialog() {
4334
- if ((xxdialogMode != null) && (xxdialogTag == '@xxmap')) { setDialogMode(0); } else { if (xxdialogMode) return false; }
4335
- var markers = [], types = ['iploc', 'wifiloc', 'gpsloc', 'userloc'], boundingBox = null;
4336
-
4337
- for (var loctype in types) {
4338
- if (currentNode[types[loctype]] != null) {
4339
- var loc = currentNode[types[loctype]].split(','), lat = parseFloat(loc[0]), lon = parseFloat(loc[1]);
4340
- if ((lat < 90) && (lat > -90) && (lon < 180) && (lon > -180)) { // Check valid lat/lon
4341
- var deviceMark = new ol.Feature({ geometry: new ol.geom.Point(ol.proj.fromLonLat([lon, lat])) });
4342
- deviceMark.setStyle(markerStyle(currentNode, parseInt(loctype) + 1));
4343
- markers.push(deviceMark);
4344
-
4345
- if (boundingBox == null) { boundingBox = [ lat, lon, lat, lon, 0 ]; } else { if (lat < boundingBox[0]) { boundingBox[0] = lat; } if (lon < boundingBox[1]) { boundingBox[1] = lon; } if (lat > boundingBox[2]) { boundingBox[2] = lat; } if (lon > boundingBox[3]) { boundingBox[3] = lon; } }
4346
- }
4347
- }
4348
- }
4349
-
4350
- // Setup the device mark layer
4351
- var vectorSource = new ol.source.Vector({ features: markers });
4352
- var vectorLayer = new ol.layer.Vector({ source: vectorSource });
4353
-
4354
- //var x = '<div><a href="https://www.google.com/maps/preview/@' + lat + ',' + lng + ',12z" rel="noreferrer noopener" target=_blank>Open in Google maps</a></div>';
4355
- var x = '<div id=d2map style=width:100%;height:300px></div>';
4356
- setDialogMode(2, "Device Location", 1, null, x, '@xxmap');
4357
-
4358
- var clng = 0, clat = 0, zoom = 8;
4359
- if (boundingBox != null) {
4360
- var clat = (boundingBox[0] + boundingBox[2]) / 2;
4361
- var clng = (boundingBox[1] + boundingBox[3]) / 2;
4362
- var cscale = Math.max(Math.abs(boundingBox[0] - boundingBox[2]), Math.abs(boundingBox[1] - boundingBox[3]));
4363
- var i = 360, zoom = -2;
4364
- while (i > cscale) { zoom++; i = i / 2; }
4365
- }
4366
-
4367
- if (markers.length == 1) { zoom = 8; }
4368
-
4369
- // Setup the map
4370
- d2map = new ol.Map({
4371
- target: 'd2map',
4372
- interactions: ol.interaction.defaults({dragPan:false, mouseWheelZoom:false}),
4373
- layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer ],
4374
- view: new ol.View({ center: ol.proj.fromLonLat([clng, clat]), zoom: zoom })
4375
- });
4376
- return false;
4377
- }
4378
-
4379
- // Show network interfaces
4380
- function p10showNodeNetInfoDialog() {
4381
- if (xxdialogMode) return false;
4382
- setDialogMode(2, "Network Interfaces", 1, null, "<div id=d2netinfo>Loading...</div>", 'if' + currentNode._id );
4383
- meshserver.send({ action: 'getnetworkinfo', nodeid: currentNode._id });
4384
- return false;
4385
- }
4386
-
4387
- // Show MeshCentral Router dialog
4388
- function p10showMeshRouterDialog() {
4389
- if (xxdialogMode) return;
4390
- var x = "<div>MeshCentral Router is a Windows tool for TCP port mapping. You can, for example, RDP into a remote device thru this server.</div><br />";
4391
- x += addHtmlValue('Win32 Executable', '<a style=cursor:pointer download href="meshagents?meshaction=winrouter" onclick="setDialogMode(0)">MeshCentralRouter.exe</a>');
4392
- setDialogMode(2, "MeshCentral Router", 1, null, x, "fileDownload");
4393
- }
4394
-
4395
- // Show MeshCmd dialog
4396
- function p10showMeshCmdDialog(mode, nodeid) {
4397
- if (xxdialogMode) return;
4398
- var y = "<select id=aginsSelect onclick=meshCmdOsClick() style=width:236px>";
4399
- y += "<option value=3>Windows (32bit)</option>";
4400
- y += "<option value=4>Windows (64bit)</option>";
4401
- y += "<option value=5>Linux x86 (32bit)</option>";
4402
- y += "<option value=6>Linux x86 (64bit)</option>";
4403
- y += "<option value=16>MacOS (64bit)</option>";
4404
- y += "<option value=25>Linux ARM, Raspberry Pi (32bit)</option>";
4405
- y += "</select>";
4406
-
4407
- var x = "";
4408
- if (mode == 0) { x += '<div>MeshCmd is a command line tool that performs lots of different operations. The action file can optionally be downloaded and edited to provide server information and credentials.<br /><br />'; }
4409
- if (mode == 1) { x += '<div>Download "meshcmd" with an action file to route traffic thru this server to this device. Make sure to edit meshaction.txt and add your account password or make any changes needed.<br /><br />'; }
4410
- x += addHtmlValue('Operating System', y);
4411
- x += addHtmlValue('MeshCmd', '<a id=meshcmddownloadid href="meshagents?meshcmd=3" download></a>');
4412
- if (mode == 0) { x += addHtmlValue('Action File', '<a href="meshagents?meshaction=generic" download>MeshAction (.txt)</a>'); }
4413
- if (mode == 1) { x += addHtmlValue('Action File', '<a href="meshagents?meshaction=route&nodeid=' + nodeid + '" download>MeshAction (.txt)</a>'); }
4414
- x += "</div>";
4415
- setDialogMode(2, ["Download MeshCmd","Network Router"][mode], 9, null, x, "fileDownload");
4416
- meshCmdOsClick();
4417
- }
4418
-
4419
- function meshCmdOsClick() {
4420
- var os = Q('aginsSelect').value, osn = '', osurl = '';
4421
- //Q('meshcmddownloadid').href = "meshagents?meshcmd=" + os;
4422
- if (os == 3) { osn = 'MeshCmd (Win32 executable)'; }
4423
- if (os == 4) { osn = 'MeshCmd (Win64 executable)'; }
4424
- if (os == 5) { osn = 'MeshCmd (Linux x86, 32bit)'; }
4425
- if (os == 6) { osn = 'MeshCmd (Linux x86, 64bit)'; }
4426
- if (os == 16) { osn = 'MeshCmd (MacOS, 64bit)'; }
4427
- if (os == 25) { osn = 'MeshCmd (Linux ARM, 32bit)'; }
4428
- QH('meshcmddownloadid', osn);
4429
- Q('meshcmddownloadid').setAttribute('href', 'meshagents?meshcmd=' + os);
4430
- }
4431
-
4432
- function p10showiconselector() {
4433
- if (xxdialogMode) return;
4434
- var mesh = meshes[currentNode.meshid];
4435
- var meshrights = mesh.links[userinfo._id].rights;
4436
- if ((meshrights & 4) == 0) return;
4437
-
4438
- var x = '<br><div style=display:inline-block;width:40px></div>';
4439
- x += '<div tabindex=0 style=display:inline-block class=i1 onclick=p10setIcon(1) onkeypress="if (event.key==\'Enter\') p10setIcon(1)"></div>';
4440
- x += '<div tabindex=0 style=display:inline-block class=i2 onclick=p10setIcon(2) onkeypress="if (event.key==\'Enter\') p10setIcon(2)"></div>';
4441
- x += '<div tabindex=0 style=display:inline-block class=i3 onclick=p10setIcon(3) onkeypress="if (event.key==\'Enter\') p10setIcon(3)"></div>';
4442
- x += '<div tabindex=0 style=display:inline-block class=i4 onclick=p10setIcon(4) onkeypress="if (event.key==\'Enter\') p10setIcon(4)"></div>';
4443
- x += '<div tabindex=0 style=display:inline-block class=i5 onclick=p10setIcon(5) onkeypress="if (event.key==\'Enter\') p10setIcon(5)"></div>';
4444
- x += '<div tabindex=0 style=display:inline-block class=i6 onclick=p10setIcon(6) onkeypress="if (event.key==\'Enter\') p10setIcon(6)"></div><br><br>';
4445
- setDialogMode(2, "Icon Selection", 0, null, x);
4446
- QV('id_dialogclose', true);
4447
- }
4448
-
4449
- function p10setIcon(icon) {
4450
- setDialogMode(0);
4451
- meshserver.send({ action: 'changedevice', nodeid: currentNode._id, icon: icon });
4452
- }
4453
-
4454
- var showEditNodeValueDialog_modes = ['Device Name', 'Hostname', 'Description', 'Tags'];
4455
- var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc', 'tags'];
4456
- var showEditNodeValueDialog_modes3 = ['', '', '', 'Tag1, Tag2, Tag3'];
4457
- function showEditNodeValueDialog(mode) {
4458
- if (xxdialogMode) return;
4459
- var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue maxlength=64 placeholder="' + showEditNodeValueDialog_modes3[mode] + '" onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
4460
- setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode);
4461
- var v = currentNode[showEditNodeValueDialog_modes2[mode]];
4462
- if (v == null) v = '';
4463
- if (Array.isArray(v)) { v = v.join(', '); }
4464
- Q('dp10devicevalue').value = v;
4465
- p10editdevicevalueValidate();
4466
- Q('dp10devicevalue').focus();
4467
- }
4468
-
4469
- function showEditNodeValueDialogEx(button, mode) {
4470
- var x = { action: 'changedevice', nodeid: currentNode._id };
4471
- x[showEditNodeValueDialog_modes2[mode]] = Q('dp10devicevalue').value;
4472
- meshserver.send(x);
4473
- }
4474
-
4475
- function p10editdevicevalueValidate(mode, e) {
4476
- var x = ((mode > 1) || (Q('dp10devicevalue').value.length > 0));
4477
- QE('idx_dlgOkButton', x);
4478
- if ((e != null) && (x == true) && (e.keyCode == 13)) { dialogclose(1); }
4479
- }
4480
-
4481
- //
4482
- // DESKTOP
4483
- //
4484
-
4485
- var desktopNode;
4486
- function setupDesktop() {
4487
- // Setup the remote desktop
4488
- if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); desktopNode = null; desktop = null; }
4489
-
4490
- // If the device desktop is already connected in multi-desktop, use that.
4491
- if ((desktopNode != currentNode) || (desktop == null)) {
4492
- var xdesk = multiDesktop[currentNode._id];
4493
- if (xdesk != null) {
4494
- // This device already has a canvas, use it.
4495
- QH('DeskParent', '');
4496
- var c = xdesk.m.CanvasId;
4497
- c.setAttribute('id', 'Desk');
4498
- c.setAttribute('onmousedown', 'dmousedown(event)');
4499
- c.setAttribute('onmouseup', 'dmouseup(event)');
4500
- c.setAttribute('onmousemove', 'dmousemove(event)');
4501
- c.removeAttribute('onclick');
4502
- Q('DeskParent').appendChild(c);
4503
- desktop = xdesk;
4504
- if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
4505
- desktop.onStateChanged = onDesktopStateChange;
4506
- desktopNode = currentNode;
4507
- onDesktopStateChange(desktop, desktop.State);
4508
- delete multiDesktop[currentNode._id];
4509
- } else {
4510
- // Device is not already connected, just setup a blank canvas
4511
- QH('DeskParent', '<canvas id=Desk oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
4512
- desktopNode = currentNode;
4513
- }
4514
- // Setup the mouse wheel
4515
- Q('Desk').addEventListener('DOMMouseScroll', function (e) { return dmousewheel(e); });
4516
- Q('Desk').addEventListener('mousewheel', function (e) { return dmousewheel(e); });
4517
- }
4518
- desktopNode = currentNode;
4519
- updateDesktopButtons();
4520
- deskAdjust();
4521
-
4522
- // On some browsers like IE, we can't save screen shots. Hide the scheenshot/capture buttons.
4523
- if (!Q('Desk')['toBlob']) { QV('deskSaveBtn', false); }
4524
- }
4525
-
4526
- // Show and enable the right buttons
4527
- function updateDesktopButtons() {
4528
- var mesh = meshes[currentNode.meshid];
4529
- var deskState = 0;
4530
- if (desktop != null) { deskState = desktop.State; }
4531
- var meshrights = mesh.links[userinfo._id].rights;
4532
-
4533
- // Show the right buttons
4534
- QV('disconnectbutton1span', (deskState != 0));
4535
- QV('connectbutton1span', (deskState == 0) && ((meshrights & 8) || (meshrights & 256)) && (mesh.mtype == 2) && (currentNode.agent.caps & 1));
4536
- QV('connectbutton1hspan', (deskState == 0) && (meshrights & 8) && ((currentNode.intelamt != null) && (mesh.mtype == 1 || currentNode.intelamt.state == 2) && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
4537
-
4538
- // Show the right settings
4539
- QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == 0) || (desktop.contype == 2)));
4540
- QV('d7meshkvm', (webRtcDesktop) || ((mesh.mtype == 2) && (currentNode.agent.caps & 1) && ((deskState == false) || (desktop.contype == 1))));
4541
-
4542
- // Enable buttons
4543
- var inputAllowed = (meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) == 0));
4544
- var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable remote desktop
4545
- QE('connectbutton1', online);
4546
- var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
4547
- QE('connectbutton1h', hwonline);
4548
- QE('deskSaveBtn', deskState == 3);
4549
- QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus));
4550
- QV('DeskClip', (currentNode.agent) && (currentNode.agent.id != 11) && (currentNode.agent.id != 16) && ((desktop == null) || (desktop.contype != 2))); // Clipboard not supported on MacOS
4551
- QE('DeskClip', deskState == 3);
4552
- QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5) && inputAllowed);
4553
- QE('DeskWD', deskState == 3);
4554
- QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5) && inputAllowed);
4555
- QE('deskkeys', deskState == 3);
4556
-
4557
- QV('DeskToolsButton', (inputAllowed) && (mesh.mtype == 2) && online);
4558
- QV('DeskChatButton', (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
4559
- QV('DeskNotifyButton', (browserfullscreen == false) && (currentNode.agent) && (currentNode.agent.id < 5) && (inputAllowed) && (mesh.mtype == 2) && online);
4560
- QV('DeskOpenWebButton', (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
4561
-
4562
- QV('DeskControlSpan', inputAllowed)
4563
- QV('deskActionsBtn', (browserfullscreen == false));
4564
- QV('deskActionsSettings', (browserfullscreen == false));
4565
- if (meshrights & 8) { Q('DeskControl').checked = (getstore('DeskControl', 1) == 1); } else { Q('DeskControl').checked = false; }
4566
- if (online == false) QV('DeskTools', false);
4567
- }
4568
-
4569
- // Debug
4570
- var autoConnectDesktopTimer = null;
4571
- function autoConnectDesktop(e) { if (autoConnectDesktopTimer == null) { autoConnectDesktopTimer = setInterval(connectDesktop, 100); } else { clearInterval(autoConnectDesktopTimer); autoConnectDesktopTimer = null; } }
4572
-
4573
- function connectDesktop(e, contype) {
4574
- p11clearConsoleMsg();
4575
- if (desktop == null) {
4576
- desktopNode = currentNode;
4577
- if (contype == 2) {
4578
- // Setup the Intel AMT remote desktop
4579
- if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop, 2); return; }
4580
- desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
4581
- desktop.debugmode = debugmode;
4582
- desktop.onStateChanged = onDesktopStateChange;
4583
- desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
4584
- desktop.m.useZRLE = (desktopsettings.encoding < 3);
4585
- desktop.m.localKeyMap = desktopsettings.localkeymap;
4586
- desktop.m.showmouse = desktopsettings.showmouse;
4587
- desktop.m.onScreenSizeChange = deskAdjust;
4588
- desktop.m.onKvmData = function (x) {
4589
- //console.log('onKvmData (' + x.length + '): ' + x);
4590
- // Send the presense probe only once if needed.
4591
- if (x.length == 0) { if (!desktop.m._sentPresence) { desktop.m._sentPresence = true; desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 })); } return; }
4592
- var data = null;
4593
- try { data = JSON.parse(x); } catch (e) { }
4594
- if ((data != null) && (data.action != null)) {
4595
- if (data.action == 'restart') {
4596
- // Clear WebRTC channel
4597
- webRtcDesktopReset();
4598
- desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 }));
4599
- } else if ((data.action == 'present') && (webRtcDesktop == null)) {
4600
- // Setup WebRTC channel
4601
- webRtcDesktop = { platform: data.platform };
4602
- var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] };
4603
- if (typeof RTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new RTCPeerConnection(configuration); }
4604
- else if (typeof webkitRTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new webkitRTCPeerConnection(configuration); }
4605
-
4606
- webRtcDesktop.webchannel = webRtcDesktop.webrtc.createDataChannel("DataChannel", {}); // { ordered: false, maxRetransmits: 2 }
4607
- webRtcDesktop.webchannel.onopen = function () {
4608
- // Switch to software KVM
4609
- //if (urlvars && urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Open'); }
4610
- console.log('WebRTC Data Channel Open');
4611
- Q('deskstatus').textContent = StatusStrs[desktop.State] + ', Soft-KVM';
4612
- desktop.m.hold(true);
4613
- webRtcDesktop.webRtcActive = true;
4614
- webRtcDesktop.softdesktop = CreateKvmDataChannel(webRtcDesktop.webchannel, CreateAgentRemoteDesktop('Desk', Q('id_mainarea')), desktop.m);
4615
- webRtcDesktop.softdesktop.m.setRotation(desktop.m.rotation);
4616
- webRtcDesktop.softdesktop.m.onScreenSizeChange = deskAdjust;
4617
- if (desktopsettings.quality) { webRtcDesktop.softdesktop.m.CompressionLevel = desktopsettings.quality; } // Number from 1 to 100. 50 or less is best.
4618
- if (desktopsettings.scaling) { webRtcDesktop.softdesktop.m.ScalingLevel = desktopsettings.scaling; }
4619
- webRtcDesktop.softdesktop.Start();
4620
-
4621
- // Check if we can get remote file access
4622
- // ###BEGIN###{DesktopInbandFiles}
4623
- /*
4624
- QV('go24', true); // Files
4625
- downloadFile = null;
4626
- p24files = webRtcDesktop.softdesktop;
4627
- p24targetpath = '';
4628
- webRtcDesktop.softdesktop.onControlMsg = onFilesControlData;
4629
- webRtcDesktop.softdesktop.sendCtrlMsg(JSON.stringify({ action: 'ls', reqid: 1, path: '' })); // Ask for the root folder
4630
- */
4631
- // ###END###{DesktopInbandFiles}
4632
- }
4633
- webRtcDesktop.webchannel.onclose = function (event) {
4634
- //if (urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Closed'); }
4635
- console.log('WebRTC Data Channel Closed');
4636
- webRtcDesktopReset();
4637
- }
4638
- webRtcDesktop.webrtc.onicecandidate = function (e) {
4639
- if (e.candidate == null) {
4640
- desktop.m.sendKvmData(JSON.stringify({ action: 'offer', ver: 1, sdp: webRtcDesktop.webrtcoffer.sdp }));
4641
- } else {
4642
- webRtcDesktop.webrtcoffer.sdp += ("a=" + e.candidate.candidate + "\r\n"); // New candidate, add it to the SDP
4643
- }
4644
- }
4645
- webRtcDesktop.webrtc.oniceconnectionstatechange = function () {
4646
- if ((webRtcDesktop != null) && (webRtcDesktop.webrtc != null) && ((webRtcDesktop.webrtc.iceConnectionState == 'disconnected') || (webRtcDesktop.webrtc.iceConnectionState == 'failed'))) { /*console.log('WebRTC ICE Failed');*/ webRtcDesktopReset(); }
4647
- }
4648
- webRtcDesktop.webrtc.createOffer(function (offer) {
4649
- // Got the offer
4650
- webRtcDesktop.webrtcoffer = offer;
4651
- webRtcDesktop.webrtc.setLocalDescription(offer, function () { }, webRtcDesktopReset);
4652
- }, webRtcDesktopReset, { mandatory: { OfferToReceiveAudio: false, OfferToReceiveVideo: false } });
4653
- } else if ((data.action == 'answer') && (webRtcDesktop != null)) {
4654
- // Complete the WebRTC channel
4655
- webRtcDesktop.webrtc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: data.sdp }), function () { }, webRtcDesktopReset);
4656
- }
4657
- }
4658
- };
4659
- desktop.Start(desktopNode._id, 16994, '*', '*', 0);
4660
- desktop.contype = 2;
4661
- } else {
4662
- // Setup the Mesh Agent remote desktop
4663
- desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, domainUrl);
4664
- desktop.debugmode = debugmode;
4665
- desktop.m.debugmode = debugmode;
4666
- desktop.attemptWebRTC = attemptWebRTC;
4667
- desktop.onStateChanged = onDesktopStateChange;
4668
- desktop.onConsoleMessageChange = function () {
4669
- p11clearConsoleMsg();
4670
- if (desktop.consoleMessage) {
4671
- QH('p11DeskConsoleMsg', EscapeHtml(desktop.consoleMessage).split('\n').join('<br />'));
4672
- QV('p11DeskConsoleMsg', true);
4673
- p11DeskConsoleMsgTimer = setTimeout(p11clearConsoleMsg, 8000);
4674
- }
4675
- }
4676
- desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
4677
- desktop.m.ScalingLevel = desktopsettings.scaling;
4678
- desktop.m.FrameRateTimer = desktopsettings.framerate;
4679
- desktop.m.onDisplayinfo = deskDisplayInfo;
4680
- desktop.m.onScreenSizeChange = deskAdjust;
4681
- desktop.Start(desktopNode._id);
4682
- desktop.contype = 1;
4683
- }
4684
- } else {
4685
- // Disconnect and clean up the remote desktop
4686
- desktop.Stop();
4687
- webRtcDesktopReset();
4688
- desktopNode = desktop = null;
4689
- }
4690
- }
4691
-
4692
- function p11clearConsoleMsg() { QV('p11DeskConsoleMsg', false); if (p11DeskConsoleMsgTimer) { clearTimeout(p11DeskConsoleMsgTimer); p11DeskConsoleMsgTimer = null; } }
4693
- function p12clearConsoleMsg() { QV('p12TermConsoleMsg', false); if (p12TermConsoleMsgTimer) { clearTimeout(p12TermConsoleMsgTimer); p12TermConsoleMsgTimer = null; } }
4694
- function p13clearConsoleMsg() { QV('p13FilesConsoleMsg', false); if (p13FilesConsoleMsgTimer) { clearTimeout(p13FilesConsoleMsgTimer); p13FilesConsoleMsgTimer = null; } }
4695
-
4696
- var webRtcDesktop = null;
4697
- function webRtcDesktopReset() {
4698
- if (webRtcDesktop == null) return;
4699
- if (webRtcDesktop.softdesktop != null) { webRtcDesktop.softdesktop.Stop(); webRtcDesktop.softdesktop = null; }
4700
- if (webRtcDesktop.webchannel != null) { try { webRtcDesktop.webchannel.close(); } catch (e) { } webRtcDesktop.webchannel = null; }
4701
- if (webRtcDesktop.webrtc != null) { try { webRtcDesktop.webrtc.close(); } catch (e) { } webRtcDesktop.webrtc = null; }
4702
- webRtcDesktop = null;
4703
- // Switch back to hardware KVM
4704
- if (desktop && desktop.m) {
4705
- desktop.m.hold(false);
4706
- Q('deskstatus').textContent = StatusStrs[desktop.State];
4707
- }
4708
- // ###BEGIN###{DesktopInbandFiles}
4709
- /*
4710
- p24files = null;
4711
- p24downloadFileCancel() // If any downloads are in process, cancel them.
4712
- p24uploadFileCancel(); // If any uploads are in process, cancel them.
4713
- QV('go24', false); // Files
4714
- if (currentView == 24) { go(14); }
4715
- */
4716
- // ###END###{DesktopInbandFiles}
4717
- }
4718
-
4719
- function onDesktopStateChange(xdesktop, state) {
4720
- var xstate = state;
4721
- if ((xstate == 3) && (xdesktop.contype == 2)) { xstate++; }
4722
- var str = StatusStrs[xstate];
4723
- if ((desktop != null) && (desktop.webRtcActive == true)) { str += ', WebRTC'; }
4724
- //if (desktop.m.stopInput == true) { str += ', Loopback'; }
4725
- QH('deskstatus', str);
4726
- switch (state) {
4727
- case 0:
4728
- // Disconnect and clean up the remote desktop
4729
- desktop.Stop();
4730
- desktopNode = desktop = null;
4731
- QV('DeskFocus', false);
4732
- QV('termdisplays', false);
4733
- deskFocusBtn.value = 'All Focus';
4734
- if (fullscreen == true) { deskToggleFull(); }
4735
- webRtcDesktopReset();
4736
- deskPreferedStickyDisplay = 0;
4737
- break;
4738
- case 2:
4739
- break;
4740
- default:
4741
- //console.log('Unknown onDesktopStateChange state', state);
4742
- break;
4743
- }
4744
- updateDesktopButtons();
4745
- deskAdjust();
4746
- setTimeout(deskAdjust, 50);
4747
- }
4748
-
4749
- function showDesktopSettings() {
4750
- if (xxdialogMode) return;
4751
- applyDesktopSettings();
4752
- updateDesktopButtons();
4753
- setDialogMode(7, "Remote Desktop Settings", 3, showDesktopSettingsChanged);
4754
- }
4755
-
4756
- function showDesktopSettingsChanged() {
4757
- desktopsettings.encoding = d7desktopmode.value;
4758
- desktopsettings.showfocus = d7showfocus.checked;
4759
- desktopsettings.showmouse = d7showcursor.checked;
4760
- desktopsettings.quality = d7bitmapquality.value;
4761
- desktopsettings.scaling = d7bitmapscaling.value;
4762
- desktopsettings.framerate = d7framelimiter.value;
4763
- desktopsettings.localkeymap = d7localKeyMap.checked;
4764
- localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
4765
- applyDesktopSettings();
4766
- if (desktop) {
4767
- if (desktop.contype == 1) {
4768
- if (desktop.State != 0) {
4769
- desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate);
4770
- }
4771
- }
4772
- if (desktop.contype == 2) {
4773
- if (desktopsettings.showfocus == false) { desktop.m.focusmode = 0; deskFocusBtn.value = 'All Focus'; }
4774
- if (desktop.State != 0) { desktop.Stop(); setTimeout(function () { connectDesktop(null, 2); }, 50); }
4775
- }
4776
- }
4777
- }
4778
-
4779
- function applyDesktopSettings() {
4780
- var r = '', ops = (features & 512)?[90,80,70,60,50,40,30,20,10,5,1]:[60,50,40,30,20,10,5,1];
4781
- for (var i in ops) { r += '<option value=' + ops[i] + '>' + ops[i] + '%</option>'; }
4782
- QH('d7bitmapquality', r);
4783
- d7desktopmode.value = desktopsettings.encoding;
4784
- d7showfocus.checked = desktopsettings.showfocus;
4785
- d7showcursor.checked = desktopsettings.showmouse;
4786
- d7bitmapquality.value = 40; // Default value
4787
- if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
4788
- d7bitmapscaling.value = desktopsettings.scaling;
4789
- if (desktopsettings.framerate) { d7framelimiter.value = desktopsettings.framerate; }
4790
- if (desktopsettings.localkeymap) { d7localKeyMap.checked = desktopsettings.localkeymap; }
4791
- QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus));
4792
- }
4793
-
4794
- // Enter browser fullscreen
4795
- function enterBrowserFullscreen(elem) {
4796
- if (elem.requestFullscreen) { elem.requestFullscreen(); }
4797
- else if (elem.msRequestFullscreen) { elem.msRequestFullscreen(); }
4798
- else if (elem.mozRequestFullScreen) { elem.mozRequestFullScreen(); }
4799
- else if (elem.webkitRequestFullscreen) { elem.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); }
4800
- }
4801
-
4802
- // Exit browser fullscreen
4803
- function exitBrowserFullscreen() {
4804
- if (document.exitFullscreen) { document.exitFullscreen(); }
4805
- else if (document.msExitFullscreen) { document.msExitFullscreen(); }
4806
- else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); }
4807
- else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); }
4808
- }
4809
-
4810
- // Return true if the browser is fullscreen. This is a delayed method that will return true/false late. Not very useful.
4811
- function isBrowserFullscreen() {
4812
- if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement) { return false; } else { return true; }
4813
- }
4814
-
4815
- var fullscreen = false;
4816
- var browserfullscreen = false;
4817
- function deskToggleFull(e) {
4818
- fullscreen = !fullscreen;
4819
- if (fullscreen) {
4820
- QC('body').add("fulldesk");
4821
- //QS('deskarea3x').height = null;
4822
- // If shift is pressed, enter browser full screen.
4823
- if (e.shiftKey == true) { enterBrowserFullscreen(Q('deskarea0')); browserfullscreen = true; }
4824
- } else {
4825
- QC('body').remove("fulldesk");
4826
- exitBrowserFullscreen();
4827
- browserfullscreen = false;
4828
- toggleFullScreen();
4829
- }
4830
- deskAdjust();
4831
- //deskAdjust();
4832
- updateDesktopButtons();
4833
- }
4834
-
4835
- function deskToggleFocus() {
4836
- desktop.m.focusmode = (desktop.m.focusmode + 64) % 192;
4837
- Q('deskFocusBtn').value = ['All Focus', 'Small Focus', 'Large Focus'][desktop.m.focusmode / 64];
4838
- }
4839
-
4840
- function deskAdjust() {
4841
- var parentH = Q('DeskParent').clientHeight, parentW = Q('DeskParent').clientWidth;
4842
- var deskH = Q('Desk').height, deskW = Q('Desk').width;
4843
-
4844
- if (deskAspectRatio == 2) {
4845
- // Scale mode
4846
- QS('Desk')['margin-top'] = null;
4847
- QS('Desk').height = '100%';
4848
- QS('Desk').width = '100%';
4849
- //QS('deskarea3x').height = null;
4850
- QS('DeskParent').overflow = 'hidden';
4851
- } else if (deskAspectRatio == 1) {
4852
- // Zoomed mode
4853
- QS('Desk')['margin-top'] = '0px';
4854
- QS('Desk').height = deskH + 'px';
4855
- QS('Desk').width = deskW + 'px';
4856
- QS('DeskParent').overflow = 'scroll';
4857
- } else {
4858
- // Fixed aspect ratio
4859
- if ((parentH / parentW) > (deskH / deskW)) {
4860
- var hNew = ((deskH * parentW) / deskW) + 'px';
4861
- //if (webPageFullScreen || fullscreen) {
4862
- //QS('deskarea3x').height = null;
4863
- //} else {
4864
- // QS('deskarea3x').height = hNew;
4865
- //QS('deskarea3x').height = null;
4866
- //}
4867
- QS('Desk').height = hNew;
4868
- QS('Desk').width = '100%';
4869
- } else {
4870
- var wNew = ((deskW * parentH) / deskH) + 'px';
4871
- if (webPageFullScreen || fullscreen) {
4872
- QS('Desk').height = null;
4873
- } else {
4874
- QS('Desk').height = '100%';
4875
- }
4876
- QS('Desk').width = wNew;
4877
- }
4878
- QS('Desk')['margin-top'] = null;
4879
- QS('DeskParent').overflow = 'hidden';
4880
- }
4881
- }
4882
-
4883
- function mdeskAdjust(mod, sw, sh, cv) {
4884
- if (!mod || !sw || !sh || !cv) return;
4885
-
4886
- // Check if we are in single desktop mode
4887
- if (cv.id == "Desk") { deskAdjust(); return; }
4888
-
4889
- // Figure out and adjust the size to fill the width of the div
4890
- var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
4891
- var realw = vsize.x + 2, tw = Q('xdevices').clientWidth - 30, xw = Math.floor(tw / realw);
4892
- xw = realw + Math.floor((tw - (xw * realw)) / xw);
4893
- vsize.y = vsize.y * (xw / vsize.x);
4894
- vsize.x = xw;
4895
- var mh = vsize.y, mw = vsize.x;
4896
- if (mod.State != 0) { mh = vsize.y; mw = (sw / sh) * vsize.y; }
4897
- QS(cv.id)['max-height'] = mh + 'px';
4898
- QS(cv.id)['max-width'] = mw + 'px';
4899
- QS(cv.id)['margin-top'] = '0';
4900
- QS(cv.id)['margin-bottom'] = '0';
4901
- }
4902
-
4903
- // Remote desktop special key combos for Windows
4904
- function deskSendKeys() {
4905
- if (xxdialogMode || desktop == null || desktop.State != 3) return;
4906
- var ks = Q('deskkeys').value;
4907
- if (ks == 0) { // WIN+Down arrow
4908
- if (desktop.contype == 2) {
4909
- desktop.m.sendkey([[0xffe7,1],[0xff54,1],[0xff54,0],[0xffe7,0]]); // Intel AMT: Meta-left down, Down arrow press, Down arrow release, Meta-left release
4910
- } else {
4911
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,40],[desktop.m.KeyAction.UP,40],[desktop.m.KeyAction.EXUP,0x5B]]); // Agent: L-Winkey press, Down arrow press, Down arrow release, L-Winkey release
4912
- }
4913
- } else if (ks == 1) { // WIN+Up arrow
4914
- if (desktop.contype == 2) {
4915
- desktop.m.sendkey([[0xffe7,1],[0xff52,1],[0xff52,0],[0xffe7,0]]); // Intel AMT: Meta-left down, Up arrow press, Up arrow release, Meta-left release
4916
- } else {
4917
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,38],[desktop.m.KeyAction.UP,38],[desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, Up arrow press, Up arrow release, L-Winkey release
4918
- }
4919
- } else if (ks == 2) { // WIN+L arrow
4920
- if (desktop.contype == 2) {
4921
- desktop.m.sendkey([[0xffe7,1],[0x6c,1],[0x6c,0],[0xffe7,0]]); // Intel AMT: Meta-left down, 'l' press, 'l' release, Meta-left release
4922
- } else {
4923
- desktop.sendCtrlMsg('{"action":"lock"}');
4924
- //desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,76],[desktop.m.KeyAction.UP,76],[desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, 'L' press, 'L' release, L-Winkey release
4925
- //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXDOWN, 0x5B);
4926
- //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.DOWN, 76);
4927
- //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.UP, 76);
4928
- //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXUP, 0x5B);
4929
- }
4930
- } else if (ks == 3) { // WIN+M arrow
4931
- if (desktop.contype == 2) {
4932
- desktop.m.sendkey([[0xffe7,1],[0x6d,1],[0x6d,0],[0xffe7,0]]); // Intel AMT: Meta-left down, 'm' press, 'm' release, Meta-left release
4933
- } else {
4934
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,77],[desktop.m.KeyAction.UP,77],[desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, 'M' press, 'M' release, L-Winkey release
4935
- }
4936
- } else if (ks == 4) { // Shift+WIN+M arrow
4937
- if (desktop.contype == 2) {
4938
- desktop.m.sendkey([[0xffe1,1],[0xffe7,1],[0x6d,1],[0x6d,0],[0xffe7,0],[0xffe1,0]]); // Intel AMT: Shift-left down, Meta-left down, 'm' press, 'm' release, Meta-left release, Shift-left release
4939
- } else {
4940
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.DOWN,16],[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,77],[desktop.m.KeyAction.UP,77],[desktop.m.KeyAction.EXUP,0x5B],[desktop.m.KeyAction.UP, 16]]); // MeshAgent: L-shift press, L-Winkey press, 'M' press, 'M' release, L-Winkey release, L-shift release
4941
- }
4942
- } else if (ks == 5) { // WIN
4943
- if (desktop.contype == 2) {
4944
- desktop.m.sendkey([[0xffe7,1],[0xffe7,0]]); // Intel AMT: Meta-left down, Meta-left release
4945
- } else {
4946
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B], [desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, L-Winkey release
4947
- }
4948
- } else if (ks == 6) { // WIN+R
4949
- if (desktop.contype == 2) {
4950
- desktop.m.sendkey([[0xffe7,1],[0x72,1],[0x72,0],[0xffe7,0]]); // Intel AMT: Meta-left down, 'r' press, 'r' release, Meta-left release
4951
- } else {
4952
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 82], [desktop.m.KeyAction.UP, 82], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, 'R' press, 'R' release, L-Winkey release
4953
- }
4954
- } else if (ks == 7) { // ALT-F4
4955
- if (desktop.contype == 2) {
4956
- desktop.m.sendkey([[0xffe9,1],[0xffc1,1],[0xffc1,0],[0xffe9,0]]); // Intel AMT: Alt down, 'F4' press, 'F4' release, Alt release
4957
- } else {
4958
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 18], [desktop.m.KeyAction.DOWN, 115], [desktop.m.KeyAction.UP, 115], [desktop.m.KeyAction.EXUP, 18]]); // MeshAgent: Alt press, 'F4' press, 'F4' release, Alt release
4959
- }
4960
- } else if (ks == 8) { // CTRL-W
4961
- if (desktop.contype == 2) {
4962
- desktop.m.sendkey([[0xffe3,1],[0x77,1],[0x77,0],[0xffe3,0]]); // Intel AMT: Ctrl down, 'w' press, 'w' release, Ctrl release
4963
- } else {
4964
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 17], [desktop.m.KeyAction.DOWN, 87], [desktop.m.KeyAction.UP, 87], [desktop.m.KeyAction.EXUP, 17]]); // MeshAgent: Ctrl press, 'W' press, 'W' release, Ctrl release
4965
- }
4966
- } else if (ks == 9) { // ALT-TAB
4967
- if (desktop.contype == 2) {
4968
- desktop.m.sendkey([[0xffe9, 1], [0xff09, 1], [0xff09, 0], [0xffe9, 0]]); // Intel AMT: Alt down, 'TAB' press, 'TAB' release, Alt release
4969
- } else {
4970
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 18], [desktop.m.KeyAction.DOWN, 9], [desktop.m.KeyAction.UP, 9], [desktop.m.KeyAction.EXUP, 18]]); // MeshAgent: Alt press, 'TAB' press, 'TAB' release, Alt release
4971
- }
4972
- } else if (ks == 10) { // CTRL-ALT-DEL
4973
- desktop.m.sendcad();
4974
- }
4975
- }
4976
-
4977
- // Show clipboard dialog
4978
- function showDeskClip() {
4979
- if (xxdialogMode || desktop == null || desktop.State != 3) return;
4980
- Q('DeskClip').blur();
4981
- var x = '';
4982
- x += '<input id=dlgClipGet type=button value="Get Clipboard" style=width:120px onclick=showDeskClipGet()>';
4983
- x += '<input id=dlgClipSet type=button value="Set Clipboard" style=width:120px onclick=showDeskClipSet()>';
4984
- x += '<div id=dlgClipStatus style="display:inline-block;margin-left:8px" ></div>';
4985
- x += '<textarea id=d2clipText style="width:100%;height:184px;resize:none" maxlength=65535></textarea>';
4986
- x += '<input type=button value="Close" style=width:80px;float:right onclick=dialogclose(0)><div style=height:26px;margin-top:3px><span id=linuxClipWarn style=display:none>Remote clipboard is valid for 60 seconds.</span> </div><div></div>';
4987
- setDialogMode(2, "Remote Clipboard", 8, null, x, 'clipboard');
4988
- Q('d2clipText').focus();
4989
- }
4990
-
4991
- function showDeskClipGet() {
4992
- if (desktop == null || desktop.State != 3) return;
4993
- meshserver.send({ action: 'msg', type: 'getclip', nodeid: currentNode._id });
4994
- }
4995
-
4996
- function showDeskClipSet() {
4997
- if (desktop == null || desktop.State != 3) return;
4998
- meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: Q('d2clipText').value });
4999
- QV('linuxClipWarn', currentNode && currentNode.agent && (currentNode.agent.id > 4) && (currentNode.agent.id != 21) && (currentNode.agent.id != 22));
This file is too large to show in full.