Translation fixed, some french strings added.

Ylian Saint-Hilaire committed Oct 21, 2019 at 15:59 UTC f7246318dc7c025489e3eda179bad599db032764
17 files changed +19803 -3928
MeshCentralServer.njsproj
+2
@@ -136,6 +136,7 @@
136 <Compile Include="public\scripts\common-0.0.1.js" />
137 <Compile Include="public\scripts\meshcentral.js" />
138 <Compile Include="redirserver.js" />
139 + <Compile Include="translate\translate.js" />
140 <Compile Include="webauthn.js" />
141 <Compile Include="webserver.js" />
142 <Compile Include="winservice.js" />
@@ -311,6 +312,7 @@
312 <Folder Include="public\styles\font-awesome\fonts\" />
313 <Folder Include="public\styles\font-awesome\less\" />
314 <Folder Include="public\styles\font-awesome\scss\" />
315 + <Folder Include="translate\" />
316 <Folder Include="typings\" />
317 <Folder Include="typings\globals\" />
318 <Folder Include="typings\globals\connect-redis\" />
package.json
+1
@@ -37,6 +37,7 @@
37 "express-handlebars": "^3.1.0",
38 "express-ws": "^4.0.0",
39 "ipcheck": "^0.1.0",
40 + "jsdom": "^15.2.0",
41 "meshcentral": "*",
42 "minimist": "^1.2.0",
43 "multiparty": "^4.2.1",
public/translations/player_fr.htm new
+537
@@ -0,0 +1,537 @@
1 +<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
2 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
3 + <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
4 + <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
5 + <meta name="apple-mobile-web-app-capable" content="yes">
6 + <meta name="format-detection" content="telephone=no">
7 + <link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
8 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
9 + <script type="text/javascript" src="scripts/agent-desktop-0.0.2.js"></script>
10 + <script type="text/javascript" src="scripts/amt-desktop-0.0.2.js"></script>
11 + <script type="text/javascript" src="scripts/amt-terminal-0.0.2.js"></script>
12 + <script type="text/javascript" src="scripts/zlib.js"></script>
13 + <script type="text/javascript" src="scripts/zlib-inflate.js"></script>
14 + <script type="text/javascript" src="scripts/zlib-adler32.js"></script>
15 + <script type="text/javascript" src="scripts/zlib-crc32.js"></script>
16 +</head>
17 +<body style="overflow:hidden;background-color:black">
18 + <div id="p11" class="noselect" style="overflow:hidden">
19 + <div id="deskarea0">
20 + <div id="deskarea1" class="areaHead">
21 + <div class="toright2">
22 + <div class="deskareaicon" title="Toggle View Mode" onclick="toggleAspectRatio(1)">⇲</div>
23 + </div>
24 + <div>
25 + <input id="OpenFileButton" type="button" value="Open File..." onclick="openfile()">
26 + <span id="deskstatus"></span>
27 + </div>
28 + </div>
29 + <div id="deskarea2" style="">
30 + <div class="areaProgress"><div id="progressbar" style=""></div></div>
31 + </div>
32 + <div id="deskarea3x" style="max-height:calc(100vh - 54px);height:calc(100vh - 54px);" onclick="togglePause()">
33 + <div id="bigok" style="display:none;left:calc((100vh / 2))"><b>✓</b></div>
34 + <div id="bigfail" style="display:none;left:calc((100vh / 2))"><b>✗</b></div>
35 + <div id="metadatadiv" style="padding:20px;color:lightgrey;text-align:left;display:none"></div>
36 + <div id="DeskParent">
37 + <canvas id="Desk" width="640" height="480"></canvas>
38 + </div>
39 + <div id="TermParent" style="display:none">
40 + <pre id="Term"></pre>
41 + </div>
42 + <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>
43 + </div>
44 + <div id="deskarea4" class="areaFoot">
45 + <div class="toright2">
46 + <div id="timespan" style="padding-top:4px;padding-right:4px">00:00:00</div>
47 + </div>
48 + <div>
49 + &nbsp;
50 + <input id="PlayButton" type="button" value="Play" disabled="disabled" onclick="play()">
51 + <input id="PauseButton" type="button" value="Pause" disabled="disabled" onclick="pause()">
52 + <input id="RestartButton" type="button" value="Restart" disabled="disabled" onclick="restart()">
53 + <select id="PlaySpeed" onchange="this.blur();">
54 + <option value="4">1/4 vitesse</option>
55 + <option value="2">1/2 vitesse</option>
56 + <option value="1" selected="">Normal Speed</option>
57 + <option value="0.5">2x vitesse</option>
58 + <option value="0.25">4x vitesse</option>
59 + <option value="0.1">10x vitesse</option>
60 + </select>
61 + </div>
62 + </div>
63 + </div>
64 + <div id="dialog" class="noselect" style="display:none">
65 + <div id="dialogHeader">
66 + <div tabindex="0" id="id_dialogclose" onclick="setDialogMode()" onkeypress="if (event.key == 'Enter') setDialogMode()">✖</div>
67 + <div id="id_dialogtitle"></div>
68 + </div>
69 + <div id="dialogBody">
70 + <div id="dialog1">
71 + <div id="id_dialogMessage" style=""></div>
72 + </div>
73 + <div id="dialog2" style="">
74 + <div id="id_dialogOptions"></div>
75 + </div>
76 + </div>
77 + <div id="idx_dlgButtonBar">
78 + <input id="idx_dlgCancelButton" type="button" value="Annuler" style="" onclick="dialogclose(0)">
79 + <input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)">
80 + <div><input id="idx_dlgDeleteButton" type="button" value="Delete" style="display:none" onclick="dialogclose(2)"></div>
81 + </div>
82 + </div>
83 + </div>
84 + <script>
85 + var recFile = null;
86 + var recFilePtr = 0;
87 + var recFileStartTime = 0;
88 + var recFileLastTime = 0;
89 + var recFileEndTime = 0;
90 + var recFileMetadata = null;
91 + var recFileProtocol = 0;
92 + var agentDesktop = null;
93 + var amtDesktop = null;
94 + var playing = false;
95 + var readState = 0;
96 + var waitTimer = null;
97 + var waitTimerArgs = null;
98 + var deskAspectRatio = 0;
99 + var currentDeltaTimeTotalSec = 0;
100 +
101 + function start() {
102 + window.onresize = deskAdjust;
103 + document.ondrop = ondrop;
104 + document.ondragover = ondragover;
105 + document.ondragleave = ondragleave;
106 + document.onkeypress = onkeypress;
107 + Q('PlaySpeed').value = 1;
108 + cleanup();
109 + }
110 +
111 + function readNextBlock(func) {
112 + if ((recFilePtr + 16) > recFile.size) { QS('progressbar').width = '100%'; func(-1); } else {
113 + var fr = new FileReader();
114 + fr.onload = function () {
115 + var type = ReadShort(this.result, 0);
116 + var flags = ReadShort(this.result, 2);
117 + var size = ReadInt(this.result, 4);
118 + var time = (ReadInt(this.result, 8) << 32) + ReadInt(this.result, 12);
119 + if ((recFilePtr + 16 + size) > recFile.size) { QS('progressbar').width = '100%'; func(-1); } else {
120 + var fr2 = new FileReader();
121 + fr2.onload = function () {
122 + recFilePtr += (16 + size);
123 + if (recFileEndTime == 0) {
124 + // File pointer progress bar
125 + QS('progressbar').width = Math.floor(100 * (recFilePtr / recFile.size)) + '%';
126 + } else {
127 + // Time progress bar
128 + QS('progressbar').width = Math.floor(((recFileLastTime - recFileStartTime) / (recFileEndTime - recFileStartTime)) * 100) + '%';
129 + }
130 + func(type, flags, time, this.result);
131 + };
132 + fr2.readAsBinaryString(recFile.slice(recFilePtr + 16, recFilePtr + 16 + size));
133 + }
134 + };
135 + fr.readAsBinaryString(recFile.slice(recFilePtr, recFilePtr + 16));
136 + }
137 + }
138 +
139 + function readLastBlock(func) {
140 + if (recFile.size < 32) { func(-1); } else {
141 + var fr = new FileReader();
142 + fr.onload = function () {
143 + var type = ReadShort(this.result, 0);
144 + var flags = ReadShort(this.result, 2);
145 + var size = ReadInt(this.result, 4);
146 + var time = (ReadInt(this.result, 8) << 32) + ReadInt(this.result, 12);
147 + if ((type == 3) && (size == 16) && (this.result.substring(16, 32) == 'MeshCentralMCREC')) { func(type, flags, time); } else { func(-1); }
148 + };
149 + fr.readAsBinaryString(recFile.slice(recFile.size - 32, recFile.size));
150 + }
151 + }
152 +
153 + function addInfo(name, value) { if (value == null) return ''; return addInfoNoEsc(name, EscapeHtml(value)); }
154 +
155 + function addInfoNoEsc(name, value) {
156 + if (value == null) return '';
157 + return '<span style=color:gray>' + EscapeHtml(name) + '</span>:&nbsp;<span style=font-size:20px>' + value + '</span><br/>';
158 + }
159 +
160 + function processFirstBlock(type, flags, time, data) {
161 + recFileProtocol = 0;
162 + if ((type != 1) || (flags != 0)) { cleanup(); return; }
163 + try { recFileMetadata = JSON.parse(data) } catch (ex) { cleanup(); return; }
164 + if ((recFileMetadata == null) || (recFileMetadata.magic != 'MeshCentralRelaySession') || (recFileMetadata.ver != 1)) { cleanup(); return; }
165 + var x = '';
166 + x += addInfo("Temps", recFileMetadata.time);
167 + if (recFileEndTime != 0) { var secs = Math.floor((recFileEndTime - time) / 1000); x += addInfo("Duration", format("{0} second{1}", secs, (secs > 1) ? 's' : '')); }
168 + x += addInfo("Nom d'utilisateur", recFileMetadata.username);
169 + x += addInfo("Identifiant d'utilisateur", recFileMetadata.userid);
170 + x += addInfo("SessionID", recFileMetadata.sessionid);
171 + if (recFileMetadata.ipaddr1 && recFileMetadata.ipaddr2) { x += addInfo("Addresses", format("{0} to {1}", recFileMetadata.ipaddr1, recFileMetadata.ipaddr2)); }
172 + if (recFileMetadata.devicename) { x += addInfo("DeviceName", recFileMetadata.devicename); }
173 + x += addInfo("NodeID", recFileMetadata.nodeid);
174 + if (recFileMetadata.protocol) {
175 + var p = recFileMetadata.protocol;
176 + if (p == 1) { p = "MeshCentral Terminal"; }
177 + else if (p == 2) { p = "MeshCentral Desktop"; }
178 + else if (p == 100) { p = "Intel&reg; AMT WSMAN"; }
179 + else if (p == 101) { p = "Intel&reg; AMT Redirection"; }
180 + x += addInfoNoEsc("Protocol", p);
181 + }
182 + QV('DeskParent', true);
183 + QV('TermParent', false);
184 + if (recFileMetadata.protocol == 1) {
185 + // MeshCentral remote terminal
186 + recFileProtocol = 1;
187 + x += '<br /><br /><span style=color:gray>' + "Press [space] to play/pause." + '</span>';
188 + QE('PlayButton', true);
189 + QE('PauseButton', false);
190 + QE('RestartButton', false);
191 + recFileStartTime = recFileLastTime = time;
192 + }
193 + else if (recFileMetadata.protocol == 2) {
194 + // MeshCentral remote desktop
195 + recFileProtocol = 2;
196 + x += '<br /><br /><span style=color:gray>' + "Press [space] to play/pause." + '</span>';
197 + QE('PlayButton', true);
198 + QE('PauseButton', false);
199 + QE('RestartButton', false);
200 + recFileStartTime = recFileLastTime = time;
201 + agentDesktop = CreateAgentRemoteDesktop('Desk');
202 + agentDesktop.onScreenSizeChange = deskAdjust;
203 + agentDesktop.State = 3;
204 + deskAdjust();
205 + }
206 + else if (recFileMetadata.protocol == 101) {
207 + // Intel AMT Redirection
208 + recFileProtocol = 101;
209 + x += '<br /><br /><span style=color:gray>Press [space] to play/pause.</span>';
210 + QE('PlayButton', true);
211 + QE('PauseButton', false);
212 + QE('RestartButton', false);
213 + recFileStartTime = recFileLastTime = time;
214 + amtDesktop = CreateAmtRemoteDesktop('Desk');
215 + amtDesktop.onScreenSizeChange = deskAdjust;
216 + amtDesktop.State = 3;
217 + amtDesktop.Start();
218 + deskAdjust();
219 + }
220 + QV('metadatadiv', true);
221 + QH('metadatadiv', x);
222 + QH('deskstatus', recFile.name);
223 + }
224 +
225 + function processBlock(type, flags, time, data) {
226 + if (type < 0) { pause(); return; }
227 + var waitTime = Math.round((time - recFileLastTime) * parseFloat(Q('PlaySpeed').value));
228 + if (waitTime < 5) {
229 + processBlockEx(type, flags, time, data);
230 + } else {
231 + waitTimerArgs = [type, flags, time, data]
232 + waitTimer = setTimeout(function () { waitTimer = null; processBlockEx(waitTimerArgs[0], waitTimerArgs[1], waitTimerArgs[2], waitTimerArgs[3]); }, waitTime);
233 + }
234 + }
235 +
236 + function processBlockEx(type, flags, time, data) {
237 + if (playing == false) return;
238 + var flagBinary = (flags & 1) != 0, flagUser = (flags & 2) != 0;
239 +
240 + // Update the clock
241 + var deltaTimeTotalSec = Math.floor((time - recFileStartTime) / 1000);
242 + if (currentDeltaTimeTotalSec != deltaTimeTotalSec) {
243 + currentDeltaTimeTotalSec = deltaTimeTotalSec;
244 + var deltaTimeHours = Math.floor(deltaTimeTotalSec / 3600);
245 + deltaTimeTotalSec -= (deltaTimeHours * 3600)
246 + var deltaTimeMinutes = Math.floor(deltaTimeTotalSec / 60);
247 + deltaTimeTotalSec -= (deltaTimeHours * 60)
248 + var deltaTimeSeconds = Math.floor(deltaTimeTotalSec);
249 + QH('timespan', pad2(deltaTimeHours) + ':' + pad2(deltaTimeMinutes) + ':' + pad2(deltaTimeSeconds))
250 + }
251 +
252 + if ((type == 2) && flagBinary && !flagUser) {
253 + // Device --> User data
254 + if (recFileProtocol == 1) {
255 + // MeshCentral Terminal
256 + agentTerminal.ProcessData(data);
257 + } else if (recFileProtocol == 2) {
258 + // MeshCentral Remote Desktop
259 + agentDesktop.ProcessData(data);
260 + } else if (recFileProtocol == 101) {
261 + // Intel AMT KVM
262 + if ((readState == 0) && (rstr2hex(data) == '4100000000000000')) {
263 + // We are not authenticated, KVM data starts here.
264 + readState = 1;
265 + if (data.length > 8) { amtDesktop.ProcessData(data.substring(8)); }
266 + } else if (readState == 1) {
267 + amtDesktop.ProcessData(data);
268 + }
269 + }
270 + } else if ((type == 2) && flagBinary && flagUser) {
271 + // User --> Device data
272 + if (recFileProtocol == 101) {
273 + // Intel AMT KVM
274 + if (rstr2hex(data) == '0000000008080001000700070003050200000000') { amtDesktop.bpp = 1; } // Switch to 1 byte per pixel.
275 + }
276 + }
277 +
278 + recFileLastTime = time;
279 + if (playing) { readNextBlock(processBlock); }
280 + }
281 +
282 + function cleanup() {
283 + recFile = null;
284 + recFilePtr = 0;
285 + recFileMetadata = null;
286 + playing = false;
287 + if (agentDesktop != null) { agentDesktop.Canvas.clearRect(0, 0, agentDesktop.CanvasId.width, agentDesktop.CanvasId.height); agentDesktop = null; }
288 + if (amtDesktop != null) { amtDesktop.canvas.clearRect(0, 0, amtDesktop.CanvasId.width, amtDesktop.CanvasId.height); amtDesktop = null; }
289 + readState = 0;
290 + waitTimerArgs = null;
291 + currentDeltaTimeTotalSec = 0;
292 + recFileEndTime = 0;
293 + agentTerminal = null;
294 + if (waitTimer != null) { clearTimeout(waitTimer); waitTimer = null; }
295 + QH('deskstatus', '');
296 + QE('PlayButton', false);
297 + QE('PauseButton', false);
298 + QE('RestartButton', false);
299 + QS('progressbar').width = '0px';
300 + QH('timespan', '00:00:00');
301 + QV('metadatadiv', true);
302 + 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>');
303 + QV('DeskParent', true);
304 + QV('TermParent', false);
305 + }
306 +
307 + function ondrop(e) {
308 + haltEvent(e);
309 + QV('bigfail', false);
310 + QV('bigok', false);
311 +
312 + // Check if these are files we can upload, remove all folders.
313 + if (e.dataTransfer == null) return;
314 + var files = [];
315 + for (var i in e.dataTransfer.files) {
316 + if ((e.dataTransfer.files[i].type != null) && (e.dataTransfer.files[i].size != null) && (e.dataTransfer.files[i].size != 0) && (e.dataTransfer.files[i].name.endsWith('.mcrec'))) {
317 + files.push(e.dataTransfer.files[i]);
318 + }
319 + }
320 + if (files.length == 0) return;
321 + cleanup();
322 + recFile = files[0];
323 + recFilePtr = 0;
324 + readNextBlock(processFirstBlock);
325 + readLastBlock(function (type, flags, time) { if (type == 3) { recFileEndTime = time; } else { recFileEndTime = 0; } });
326 + }
327 +
328 + var dragtimer = null;
329 + function ondragover(e) {
330 + haltEvent(e);
331 + if (dragtimer != null) { clearTimeout(dragtimer); dragtimer = null; }
332 + var ac = true;
333 + QV('bigok', ac);
334 + QV('bigfail', !ac);
335 + }
336 +
337 + function ondragleave(e) {
338 + haltEvent(e);
339 + dragtimer = setTimeout(function () { QV('bigfail', false); QV('bigok', false); dragtimer = null; }, 10);
340 + }
341 +
342 + function onkeypress(e) {
343 + if (xxdialogMode) return;
344 + if (e.key == ' ') { togglePause(); haltEvent(e); }
345 + if (e.key == '1') { Q('PlaySpeed').value = 4; haltEvent(e); }
346 + if (e.key == '2') { Q('PlaySpeed').value = 2; haltEvent(e); }
347 + if (e.key == '3') { Q('PlaySpeed').value = 1; haltEvent(e); }
348 + if (e.key == '4') { Q('PlaySpeed').value = 0.5; haltEvent(e); }
349 + if (e.key == '5') { Q('PlaySpeed').value = 0.25; haltEvent(e); }
350 + if (e.key == '6') { Q('PlaySpeed').value = 0.1; haltEvent(e); }
351 + if (e.key == '0') { pause(); restart(); haltEvent(e); }
352 + }
353 +
354 + function openfile() {
355 + var x = '<input type=file name=files id=p2fileinput style=width:100% accept=".mcrec" onchange="openfileChanged()" />';
356 + setDialogMode(2, "Open File...", 3, openfileEx, x);
357 + QE('idx_dlgOkButton', false);
358 + }
359 +
360 + function openfileEx() {
361 + var xfiles = Q('p2fileinput').files;
362 + if (xfiles != null) { var files = []; for (var i in xfiles) { if ((xfiles[i].type != null) && (xfiles[i].size != null) && (xfiles[i].size != 0) && (xfiles[i].name.endsWith('.mcrec'))) { files.push(xfiles[i]); } } }
363 + if (files.length == 0) return;
364 + cleanup();
365 + recFile = files[0];
366 + recFilePtr = 0;
367 + readNextBlock(processFirstBlock);
368 + readLastBlock(function (type, flags, time) { if (type == 3) { recFileEndTime = time; } else { recFileEndTime = 0; } });
369 + Q('OpenFileButton').blur();
370 + }
371 +
372 + function openfileChanged() {
373 + var xfiles = Q('p2fileinput').files;
374 + if (xfiles != null) { var files = []; for (var i in xfiles) { if ((xfiles[i].type != null) && (xfiles[i].size != null) && (xfiles[i].size != 0) && (xfiles[i].name.endsWith('.mcrec'))) { files.push(xfiles[i]); } } }
375 + QE('idx_dlgOkButton', files.length == 1);
376 + }
377 +
378 + function togglePause() {
379 + if (recFile != null) { if (playing == true) { pause(); } else { if (recFilePtr != recFile.size) { play(); } } } return false;
380 + }
381 +
382 + function play() {
383 + Q('PlayButton').blur();
384 + if ((playing == true) || (recFileProtocol == 0)) return;
385 + playing = true;
386 + QV('metadatadiv', false);
387 + QE('PlayButton', false);
388 + QE('PauseButton', true);
389 + QE('RestartButton', false);
390 + if ((recFileProtocol == 1) && (agentTerminal == null)) {
391 + QV('DeskParent', false);
392 + QV('TermParent', true);
393 + agentTerminal = CreateAmtRemoteTerminal('Term', {});
394 + agentTerminal.State = 3;
395 + }
396 + readNextBlock(processBlock);
397 + }
398 +
399 + function pause() {
400 + Q('PauseButton').blur();
401 + if (playing == false) return;
402 + playing = false;
403 + QE('PlayButton', recFilePtr != recFile.size);
404 + QE('PauseButton', false);
405 + QE('RestartButton', recFilePtr != 0);
406 + if (waitTimer != null) {
407 + clearTimeout(waitTimer);
408 + waitTimer = null;
409 + processBlockEx(waitTimerArgs[0], waitTimerArgs[1], waitTimerArgs[2], waitTimerArgs[3]);
410 + waitTimerArgs = null;
411 + }
412 + }
413 +
414 + function restart() {
415 + Q('RestartButton').blur();
416 + if (playing == true) return;
417 + recFilePtr = 0;
418 + readState = 0;
419 + currentDeltaTimeTotalSec = 0;
420 + QV('metadatadiv', true);
421 + QE('PlayButton', true);
422 + QE('PauseButton', false);
423 + QE('RestartButton', false);
424 + QS('progressbar').width = '0px';
425 + QH('timespan', '00:00:00');
426 + QV('DeskParent', true);
427 + QV('TermParent', false);
428 + if (agentDesktop) {
429 + agentDesktop.Canvas.clearRect(0, 0, agentDesktop.CanvasId.width, agentDesktop.CanvasId.height);
430 + } else if (amtDesktop) {
431 + amtDesktop.canvas.clearRect(0, 0, amtDesktop.CanvasId.width, amtDesktop.CanvasId.height);
432 + amtDesktop = CreateAmtRemoteDesktop('Desk');
433 + amtDesktop.onScreenSizeChange = deskAdjust;
434 + amtDesktop.State = 3;
435 + amtDesktop.Start();
436 + } else if (agentTerminal) {
437 + agentTerminal = null;
438 + }
439 + }
440 +
441 + function clearConsoleMsg() { QH('p11DeskConsoleMsg', ''); }
442 +
443 + // Toggle the web page to full screen
444 + function toggleAspectRatio(toggle) {
445 + if (toggle === 1) { deskAspectRatio = ((deskAspectRatio + 1) % 3); }
446 + deskAdjust();
447 + }
448 +
449 + function deskAdjust() {
450 + var parentH = Q('DeskParent').clientHeight, parentW = Q('DeskParent').clientWidth;
451 + var deskH = Q('Desk').height, deskW = Q('Desk').width;
452 +
453 + if (deskAspectRatio == 2) {
454 + // Scale mode
455 + QS('Desk')['margin-top'] = null;
456 + QS('Desk').height = '100%';
457 + QS('Desk').width = '100%';
458 + QS('DeskParent').overflow = 'hidden';
459 + } else if (deskAspectRatio == 1) {
460 + // Zoomed mode
461 + QS('Desk')['margin-top'] = '0px';
462 + //QS('Desk')['margin-left'] = '0px';
463 + QS('Desk').height = deskH + 'px';
464 + QS('Desk').width = deskW + 'px';
465 + QS('DeskParent').overflow = 'scroll';
466 + } else {
467 + // Fixed aspect ratio
468 + if ((parentH / parentW) > (deskH / deskW)) {
469 + var hNew = ((deskH * parentW) / deskW) + 'px';
470 + //if (webPageFullScreen || fullscreen) {
471 + //QS('deskarea3x').height = null;
472 + //} else {
473 + // QS('deskarea3x').height = hNew;
474 + //QS('deskarea3x').height = null;
475 + //}
476 + QS('Desk').height = hNew;
477 + QS('Desk').width = '100%';
478 + } else {
479 + var wNew = ((deskW * parentH) / deskH) + 'px';
480 + //if (webPageFullScreen || fullscreen) {
481 + //QS('Desk').height = null;
482 + //} else {
483 + QS('Desk').height = '100%';
484 + //}
485 + QS('Desk').width = wNew;
486 + }
487 + QS('Desk')['margin-top'] = null;
488 + QS('DeskParent').overflow = 'hidden';
489 + }
490 + }
491 +
492 + //
493 + // POPUP DIALOG
494 + //
495 +
496 + // null = Hidden, 1 = Generic Message
497 + var xxdialogMode;
498 + var xxdialogFunc;
499 + var xxdialogButtons;
500 + var xxdialogTag;
501 + var xxcurrentView = -1;
502 +
503 + // Display a dialog box
504 + // Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
505 + function setDialogMode(x, y, b, f, c, tag) {
506 + xxdialogMode = x;
507 + xxdialogFunc = f;
508 + xxdialogButtons = b;
509 + xxdialogTag = tag;
510 + QE('idx_dlgOkButton', true);
511 + QV('idx_dlgOkButton', b & 1);
512 + QV('idx_dlgCancelButton', b & 2);
513 + QV('id_dialogclose', (b & 2) || (b & 8));
514 + QV('idx_dlgDeleteButton', b & 4);
515 + QV('idx_dlgButtonBar', b & 7);
516 + if (y) QH('id_dialogtitle', y);
517 + for (var i = 1; i < 3; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
518 + QV('dialog', x);
519 + if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
520 + }
521 +
522 + function dialogclose(x) {
523 + var f = xxdialogFunc, b = xxdialogButtons, t = xxdialogTag;
524 + setDialogMode();
525 + if (((b & 8) || x) && f) f(x, t);
526 + }
527 +
528 + function messagebox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
529 + function statusbox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t); }
530 + function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
531 + function pad2(num) { var s = '00' + num; return s.substr(s.length - 2); }
532 + function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
533 +
534 + start();
535 + </script>
536 +
537 +</body></html>
\ No newline at end of file
translate/translate.js
-2
@@ -25,8 +25,6 @@ var meshCentralSourceFiles = [
25 "../views/login-mobile.handlebars",
26 "../views/message.handlebars",
27 "../views/messenger.handlebars",
28 - "../views/terms.handlebars",
29 - "../views/terms-mobile.handlebars",
28 "../public/player.htm"
29 ];
30
translate/translate.json
+3959 -3862
@@ -20,9413 +20,9510 @@
20 ]
21 },
22 {
23 - "en": "User interface selection",
23 + "en": "Kirghiz",
24 "xloc": [
25 - "agentinvite.handlebars->container->topbar",
26 - "default.handlebars->container->topbar->1->1",
27 - "error404.handlebars->container->topbar",
28 - "login.handlebars->container->topbar",
29 - "terms.handlebars->container->topbar"
25 + "default.handlebars->13->767"
26 ]
27 },
28 {
33 - "en": "♦",
29 + "en": "Storage limit exceed",
30 "xloc": [
35 - "agentinvite.handlebars->container->topbar->uiMenuButton",
36 - "default.handlebars->container->topbar->1->1->uiMenuButton",
37 - "error404.handlebars->container->topbar->uiMenuButton",
38 - "login.handlebars->container->topbar->uiMenuButton",
39 - "terms.handlebars->container->topbar->uiMenuButton"
31 + "default.handlebars->13->1068"
32 ]
33 },
34 {
43 - "en": "Left bar interface",
35 + "en": "Focus All",
36 "xloc": [
45 - "agentinvite.handlebars->container->topbar->uiMenuButton->uiMenu",
46 - "default.handlebars->container->topbar->1->1->uiMenuButton->uiMenu",
47 - "error404.handlebars->container->topbar->uiMenuButton->uiMenu",
48 - "login.handlebars->container->topbar->uiMenuButton->uiMenu",
49 - "terms.handlebars->container->topbar->uiMenuButton->uiMenu"
37 + "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
38 ]
39 },
40 {
53 - "en": "Top bar interface",
41 + "en": "Reset Password",
42 "xloc": [
55 - "agentinvite.handlebars->container->topbar->uiMenuButton->uiMenu",
56 - "default.handlebars->container->topbar->1->1->uiMenuButton->uiMenu",
57 - "error404.handlebars->container->topbar->uiMenuButton->uiMenu",
58 - "login.handlebars->container->topbar->uiMenuButton->uiMenu",
59 - "terms.handlebars->container->topbar->uiMenuButton->uiMenu"
43 + "login.handlebars->container->column_l->centralTable->1->0->logincell->resetpasswordpanel->1->7->1->6->1->1",
44 + "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->resetpasswordpanel->1->7->1->6->1->1"
45 ]
46 },
47 {
63 - "en": "Fixed width interface",
48 + "en": "Delete selected item?",
49 "xloc": [
65 - "agentinvite.handlebars->container->topbar->uiMenuButton->uiMenu",
66 - "default.handlebars->container->topbar->1->1->uiMenuButton->uiMenu",
67 - "error404.handlebars->container->topbar->uiMenuButton->uiMenu",
68 - "login.handlebars->container->topbar->uiMenuButton->uiMenu",
69 - "terms.handlebars->container->topbar->uiMenuButton->uiMenu"
50 + "default.handlebars->13->609",
51 + "default.handlebars->13->1089",
52 + "default-mobile.handlebars->9->80",
53 + "default-mobile.handlebars->9->249"
54 ]
55 },
56 {
73 - "en": "Toggle night mode",
57 + "en": "Faeroese",
58 "xloc": [
75 - "agentinvite.handlebars->container->topbar->uiMenuButton->uiMenu",
76 - "default.handlebars->container->topbar->1->1->uiMenuButton->uiMenu",
77 - "error404.handlebars->container->topbar->uiMenuButton->uiMenu",
78 - "login.handlebars->container->topbar->uiMenuButton->uiMenu",
79 - "terms.handlebars->container->topbar->uiMenuButton->uiMenu"
59 + "default.handlebars->13->727"
60 ]
61 },
62 {
83 - "en": "Remote Agent Installation",
63 + "en": "MeshServerRootCert.cer",
64 "xloc": [
85 - "agentinvite.handlebars->container->column_l->1"
65 + "default.handlebars->13->225"
66 ]
67 },
68 {
89 - "en": "You have been invited to install a software that will allow a remote operator to fully access your computer remotely including the desktop and files.\n Only follow the instructions below if this invitation was expected and you know who will be accessing your computer.\n Selecting your operation system and follow the instructions below.",
69 + "en": "Luxembourgish",
70 "xloc": [
91 - "agentinvite.handlebars->container->column_l->3"
71 + "default.handlebars->13->775"
72 ]
73 },
74 {
95 - "en": "Windows 64bit",
75 + "en": "Turkmen",
76 "xloc": [
97 - "agentinvite.handlebars->container->column_l->5->1->twintab64"
77 + "default.handlebars->13->849"
78 ]
79 },
80 {
101 - "en": "Windows 32bit",
81 + "en": "Spanish (Colombia)",
82 "xloc": [
103 - "agentinvite.handlebars->container->column_l->5->1->twintab32"
83 + "default.handlebars->13->820"
84 ]
85 },
86 {
107 - "en": "Linux",
87 + "en": "Console",
88 "xloc": [
109 - "agentinvite.handlebars->container->column_l->5->1->tlinuxtab",
110 - "agentinvite.handlebars->container->column_l->5->linuxtab->1"
89 + "default.handlebars->contextMenu->cxconsole",
90 + "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevConsole",
91 + "default.handlebars->container->topbar->1->1->ServerSubMenuSpan->ServerSubMenu->1->0->ServerConsole"
92 ]
93 },
94 {
114 - "en": "MacOS",
95 + "en": "Windows MinCore service",
96 "xloc": [
116 - "agentinvite.handlebars->container->column_l->5->1->tmacostab"
97 + "default.handlebars->13->412",
98 + "default-mobile.handlebars->9->162"
99 ]
100 },
101 {
120 - "en": "Microsoft™ Windows 64bit",
102 + "en": "Perform power actions on the device",
103 "xloc": [
122 - "agentinvite.handlebars->container->column_l->5->wintab64->1"
104 + "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1",
105 + "default.handlebars->container->column_l->p12->termTable->1->1->0->1->1",
106 + "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->1",
107 + "default.handlebars->13->464"
108 ]
109 },
110 {
126 - "en": "Download the software here",
111 + "en": "Unable to scan this address range.",
112 "xloc": [
128 - "agentinvite.handlebars->container->column_l->5->wintab64->3->win64url",
129 - "agentinvite.handlebars->container->column_l->5->wintab32->3->win32url"
113 + "default.handlebars->13->123"
114 ]
115 },
116 {
133 - "en": ", run it and press \"Install\" or \"Connect\".",
117 + "en": "MQTT channel connected",
118 "xloc": [
135 - "agentinvite.handlebars->container->column_l->5->wintab64->3",
136 - "agentinvite.handlebars->container->column_l->5->wintab32->3"
119 + "default.handlebars->13->494",
120 + "default-mobile.handlebars->9->200"
121 ]
122 },
123 {
140 - "en": "Microsoft™ Windows 32bit",
124 + "en": "Windows 64bit console",
125 "xloc": [
142 - "agentinvite.handlebars->container->column_l->5->wintab32->1"
126 + "default.handlebars->13->392",
127 + "default-mobile.handlebars->9->142"
128 ]
129 },
130 {
146 - "en": "To install, cut and paste the following command in a root terminal.",
131 + "en": "Add a new Intel&reg; AMT computer that is located on the internet.",
132 "xloc": [
148 - "agentinvite.handlebars->container->column_l->5->linuxtab->3"
133 + "default.handlebars->13->179",
134 + "default.handlebars->13->954"
135 ]
136 },
137 {
152 - "en": "Copy to clipboard",
138 + "en": "Corsican",
139 "xloc": [
154 - "agentinvite.handlebars->container->column_l->5->linuxtab",
155 - "agentinvite.handlebars->container->column_l->5->linuxtab"
140 + "default.handlebars->13->705"
141 ]
142 },
143 {
159 - "en": "To uninstall, cut and paste the following command as root.",
144 + "en": "Special Keys",
145 "xloc": [
161 - "agentinvite.handlebars->container->column_l->5->linuxtab->9"
146 + "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea4->1->3",
147 + "default-mobile.handlebars->9->227"
148 ]
149 },
150 {
165 - "en": "Apple™ MacOS",
151 + "en": "Terminal Notify",
152 "xloc": [
167 - "agentinvite.handlebars->container->column_l->5->macostab->1"
153 + "default.handlebars->13->933"
154 ]
155 },
156 {
171 - "en": "Download the installer here",
157 + "en": "Romanian (Moldavia)",
158 "xloc": [
173 - "agentinvite.handlebars->container->column_l->5->macostab->3->macosurl"
159 + "default.handlebars->13->802"
160 ]
161 },
162 {
177 - "en": ", right click on it or press \"control\" and click on the file. Then select \"Open\" and follow the instructions.",
163 + "en": "Reset devices",
164 "xloc": [
179 - "agentinvite.handlebars->container->column_l->5->macostab->3"
165 + "default.handlebars->13->344"
166 ]
167 },
168 {
183 - "en": "{{{domain}}}",
169 + "en": "All Focus",
170 "xloc": [
185 - "agentinvite.handlebars->3->1"
171 + "default.handlebars->13->554",
172 + "default.handlebars->13->556",
173 + "default.handlebars->13->559"
174 ]
175 },
176 {
189 - "en": "{{{domainurl}}}",
177 + "en": "Administrative Realms",
178 "xloc": [
191 - "agentinvite.handlebars->3->2"
179 + "default.handlebars->13->1167"
180 ]
181 },
182 {
195 - "en": "{{{meshid}}}",
183 + "en": "New Device Group",
184 "xloc": [
197 - "agentinvite.handlebars->3->3"
185 + "default.handlebars->13->524",
186 + "default.handlebars->13->886",
187 + "default.handlebars->13->898",
188 + "default-mobile.handlebars->9->47"
189 ]
190 },
191 {
201 - "en": "{{{serverport}}}",
192 + "en": "Device is detected but power state could not be obtained.",
193 "xloc": [
203 - "agentinvite.handlebars->3->4"
194 + "default.handlebars->13->317"
195 ]
196 },
197 {
207 - "en": "{{{serverhttps}}}",
198 + "en": "Serial",
199 "xloc": [
209 - "agentinvite.handlebars->3->5"
200 + "default.handlebars->13->33"
201 ]
202 },
203 {
213 - "en": "{{{servernoproxy}}}",
204 + "en": "Shift+Win+M",
205 "xloc": [
215 - "agentinvite.handlebars->3->6"
206 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->13",
207 + "default-mobile.handlebars->dialog->3->dialog3->deskkeys->15"
208 ]
209 },
210 {
219 - "en": "{{{installflags}}}",
211 + "en": "4x Speed",
212 + "fr": "4x vitesse",
213 "xloc": [
221 - "agentinvite.handlebars->3->7"
214 + "player.htm->p11->deskarea0->deskarea4->3->PlaySpeed->9"
215 ]
216 },
217 {
225 - "en": "{{{meshname}}}",
218 + "en": "(wget http://",
219 "xloc": [
227 - "agentinvite.handlebars->3->8"
220 + "agentinvite.handlebars->3->39",
221 + "agentinvite.handlebars->3->44"
222 ]
223 },
224 {
231 - "en": "menu_stack",
225 + "en": "Android x86",
226 "xloc": [
233 - "agentinvite.handlebars->3->9",
234 - "agentinvite.handlebars->3->14",
235 - "agentinvite.handlebars->3->15",
236 - "terms.handlebars->3->2",
237 - "terms.handlebars->3->7",
238 - "terms.handlebars->3->8"
227 + "default.handlebars->13->402",
228 + "default-mobile.handlebars->9->152"
229 ]
230 },
231 {
242 - "en": "fullscreen",
232 + "en": "French (Luxembourg)",
233 "xloc": [
244 - "agentinvite.handlebars->3->10",
245 - "agentinvite.handlebars->3->12",
246 - "terms.handlebars->3->3",
247 - "terms.handlebars->3->5"
234 + "default.handlebars->13->735"
235 ]
236 },
237 {
251 - "en": "arg_hide",
238 + "en": "Select All",
239 "xloc": [
253 - "agentinvite.handlebars->3->11",
254 - "agentinvite.handlebars->3->13",
255 - "default.handlebars->13->1265",
256 - "terms.handlebars->3->4",
257 - "terms.handlebars->3->6"
240 + "default.handlebars->meshContextMenu->cxselectall",
241 + "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar",
242 + "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
243 + "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
244 + "default.handlebars->13->338",
245 + "default.handlebars->13->601",
246 + "default.handlebars->13->603",
247 + "default.handlebars->13->1082"
248 ]
249 },
250 {
261 - "en": "tabcontent",
251 + "en": " active",
252 + "fr": "actif",
253 "xloc": [
263 - "agentinvite.handlebars->3->16"
254 + "agentinvite.handlebars->3->19",
255 + "agentinvite.handlebars->3->21",
256 + "agentinvite.handlebars->3->22"
257 ]
258 },
259 {
267 - "en": "none",
260 + "en": "Unknown State",
261 + "fr": "Etat inconnu",
262 "xloc": [
269 - "agentinvite.handlebars->3->17"
263 + "default.handlebars->13->425",
264 + "default-mobile.handlebars->9->175"
265 ]
266 },
267 {
273 - "en": "tablinks",
268 + "en": "Antivirus",
269 + "fr": "Antivirus",
270 "xloc": [
275 - "agentinvite.handlebars->3->18"
271 + "default.handlebars->13->449"
272 ]
273 },
274 {
279 - "en": " active",
275 + "en": "Toggle F1 to F10 keys emulation type",
276 "xloc": [
281 - "agentinvite.handlebars->3->19",
282 - "agentinvite.handlebars->3->21",
283 - "agentinvite.handlebars->3->22"
277 + "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSettingsButtons"
278 ]
279 },
280 {
287 - "en": "block",
281 + "en": "Agent",
282 + "fr": "Agent",
283 "xloc": [
289 - "agentinvite.handlebars->3->20"
284 + "default.handlebars->container->column_l->p15->consoleTable->1->6->1->1->1->0->p15outputselecttd->p15outputselect->1",
285 + "default.handlebars->13->143",
286 + "default.handlebars->13->327",
287 + "default-mobile.handlebars->9->118",
288 + "default-mobile.handlebars->9->171",
289 + "default-mobile.handlebars->9->187"
290 ]
291 },
292 {
293 - "en": ":",
293 + "en": "Intel&reg; AMT Tag",
294 "xloc": [
295 - "agentinvite.handlebars->3->23",
296 - "agentinvite.handlebars->3->38"
295 + "default.handlebars->13->444"
296 ]
297 },
298 {
300 - "en": "(wget https://",
299 + "en": "No location found.",
300 "xloc": [
302 - "agentinvite.handlebars->3->24",
303 - "agentinvite.handlebars->3->29"
301 + "default.handlebars->13->372"
302 ]
303 },
304 {
307 - "en": "meshagents?script=1 --no-check-certificate -O ./meshinstall.sh || wget https://",
305 + "en": "To add a new computer to device group \\\"{0}\\\", download the mesh agent and install it the computer to manage. This agent has server and device group information embedded within it.",
306 "xloc": [
309 - "agentinvite.handlebars->3->25",
310 - "agentinvite.handlebars->3->30"
307 + "default.handlebars->13->280"
308 ]
309 },
310 {
314 - "en": "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://",
311 + "en": "Reset map view",
312 "xloc": [
316 - "agentinvite.handlebars->3->26"
313 + "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devMapToolbar"
314 ]
315 },
316 {
320 - "en": " '",
317 + "en": "Power Actions...",
318 "xloc": [
322 - "agentinvite.handlebars->3->27",
323 - "agentinvite.handlebars->3->34",
324 - "agentinvite.handlebars->3->42",
325 - "agentinvite.handlebars->3->49"
326 - ]
327 - },
328 - {
329 - "en": "'\\r\\n",
330 - "xloc": [
331 - "agentinvite.handlebars->3->28",
332 - "agentinvite.handlebars->3->35",
333 - "agentinvite.handlebars->3->43",
334 - "agentinvite.handlebars->3->50"
319 + "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1",
320 + "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea4->1->3"
321 ]
322 },
323 {
338 - "en": "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\\r\\n",
324 + "en": "Identifier",
325 "xloc": [
340 - "agentinvite.handlebars->3->31"
326 + "default.handlebars->13->35"
327 ]
328 },
329 {
344 - "en": "wget https://",
330 + "en": "Spanish (Puerto Rico)",
331 "xloc": [
346 - "agentinvite.handlebars->3->32",
347 - "agentinvite.handlebars->3->36"
332 + "default.handlebars->13->832"
333 ]
334 },
335 {
351 - "en": "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://",
336 + "en": "meshagents?script=1 --no-proxy -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\\r\\n",
337 "xloc": [
353 - "agentinvite.handlebars->3->33"
338 + "agentinvite.handlebars->3->46"
339 ]
340 },
341 {
357 - "en": "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\\r\\n",
342 + "en": "Albanian",
343 "xloc": [
359 - "agentinvite.handlebars->3->37"
344 + "default.handlebars->13->666"
345 ]
346 },
347 {
363 - "en": "(wget http://",
348 + "en": "10x Speed",
349 + "fr": "10x vitesse",
350 "xloc": [
365 - "agentinvite.handlebars->3->39",
366 - "agentinvite.handlebars->3->44"
351 + "player.htm->p11->deskarea0->deskarea4->3->PlaySpeed->11"
352 ]
353 },
354 {
370 - "en": "meshagents?script=1 -O ./meshinstall.sh || wget http://",
355 + "en": "Dutch (Standard)",
356 "xloc": [
372 - "agentinvite.handlebars->3->40",
373 - "agentinvite.handlebars->3->45"
357 + "default.handlebars->13->710"
358 ]
359 },
360 {
377 - "en": "meshagents?script=1 --no-proxy -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh http://",
361 + "en": "1 session",
362 + "fr": "1 session",
363 "xloc": [
379 - "agentinvite.handlebars->3->41"
364 + "default.handlebars->13->1120"
365 ]
366 },
367 {
383 - "en": "meshagents?script=1 --no-proxy -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\\r\\n",
368 + "en": "Add YubiKey&reg; OTP",
369 "xloc": [
385 - "agentinvite.handlebars->3->46"
370 + "default.handlebars->13->105"
371 ]
372 },
373 {
389 - "en": "wget http://",
374 + "en": "Realms",
375 "xloc": [
391 - "agentinvite.handlebars->3->47",
392 - "agentinvite.handlebars->3->51"
376 + "default.handlebars->13->1165"
377 ]
378 },
379 {
396 - "en": "meshagents?script=1 --no-proxy -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh http://",
380 + "en": "UTF8 Terminal",
381 + "fr": "Terminal UTF8",
382 "xloc": [
398 - "agentinvite.handlebars->3->48"
383 + "default.handlebars->13->587"
384 ]
385 },
386 {
402 - "en": "meshagents?script=1 --no-proxy -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\\r\\n",
387 + "en": "Intel (F10 = ESC+[OM)",
388 "xloc": [
404 - "agentinvite.handlebars->3->52"
389 + "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSettingsButtons",
390 + "default.handlebars->13->590"
391 ]
392 },
393 {
408 - "en": "Information",
394 + "en": "Verify email",
395 "xloc": [
410 - "default.handlebars->contextMenu->cxinfo->0"
396 + "default.handlebars->container->column_l->p2->p2AccountActions->3->verifyEmailId->0",
397 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->7->1->verifyEmailId->0"
398 ]
399 },
400 {
414 - "en": "Desktop",
401 + "en": "MQTT disconnected",
402 "xloc": [
416 - "default.handlebars->contextMenu->cxdesktop",
417 - "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevDesktop",
418 - "default.handlebars->13->357",
419 - "default.handlebars->13->1006"
403 + "default.handlebars->13->122"
404 ]
405 },
406 {
423 - "en": "Terminal",
407 + "en": "Access to server files",
408 "xloc": [
425 - "default.handlebars->contextMenu->cxterminal",
426 - "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevTerminal",
427 - "default.handlebars->13->358",
428 - "default.handlebars->13->1010"
409 + "default.handlebars->13->1180"
410 ]
411 },
412 {
432 - "en": "Files",
413 + "en": "Don\\'t configure",
414 "xloc": [
434 - "default.handlebars->contextMenu->cxfiles",
435 - "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevFiles",
436 - "default.handlebars->13->1013"
415 + "default.handlebars->13->989",
416 + "default.handlebars->13->994"
417 ]
418 },
419 {
440 - "en": "Events",
420 + "en": "YubiKey&trade; OTP",
421 "xloc": [
442 - "default.handlebars->contextMenu->cxevents",
443 - "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevEvents",
444 - "default.handlebars->container->topbar->1->1->UserSubMenuSpan->UserSubMenu->1->0->UserEvents"
422 + "default.handlebars->13->661"
423 ]
424 },
425 {
448 - "en": "Console",
426 + "en": "Send MQTT message",
427 "xloc": [
450 - "default.handlebars->contextMenu->cxconsole",
451 - "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevConsole",
452 - "default.handlebars->container->topbar->1->1->ServerSubMenuSpan->ServerSubMenu->1->0->ServerConsole"
428 + "default.handlebars->13->521"
429 ]
430 },
431 {
456 - "en": "Multi-Desktop",
432 + "en": "This will add an entry to this device\\'s event log.",
433 "xloc": [
458 - "default.handlebars->contextMenu->cxmdesktop"
434 + "default.handlebars->13->497"
435 ]
436 },
437 {
462 - "en": "Select All",
438 + "en": "Connectivity",
439 "xloc": [
464 - "default.handlebars->meshContextMenu->cxselectall",
465 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar",
466 - "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
467 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
468 - "default.handlebars->13->338",
469 - "default.handlebars->13->601",
470 - "default.handlebars->13->603",
471 - "default.handlebars->13->1082"
440 + "default.handlebars->13->138",
441 + "default.handlebars->13->155",
442 + "default.handlebars->13->461",
443 + "default-mobile.handlebars->9->192"
444 ]
445 },
446 {
475 - "en": "Select None",
447 + "en": "licensed under the",
448 "xloc": [
477 - "default.handlebars->meshContextMenu->cxselectnone",
478 - "default.handlebars->13->337",
479 - "default.handlebars->13->602",
480 - "default.handlebars->13->1081"
449 + "terms.handlebars->container->column_l->75->1",
450 + "terms-mobile.handlebars->container->page_content->column_l->75->1"
451 ]
452 },
453 {
484 - "en": "Normal Connect",
454 + "en": "Klingon",
455 "xloc": [
486 - "default.handlebars->termShellContextMenu->cxtermnorm"
456 + "default.handlebars->13->768"
457 ]
458 },
459 {
490 - "en": "PowerShell Connect",
460 + "en": "To remove a mesh agent, run the following command. Root credentials will be needed.",
461 "xloc": [
492 - "default.handlebars->termShellContextMenu->cxtermps"
462 + "default.handlebars->13->301"
463 ]
464 },
465 {
496 - "en": "Click to view current notifications",
466 + "en": "Group1, Group2, Group3",
467 "xloc": [
498 - "default.handlebars->container->masthead->5"
468 + "default-mobile.handlebars->9->223"
469 ]
470 },
471 {
502 - "en": "My Devices",
472 + "en": "SessionID",
473 "xloc": [
504 - "default.handlebars->container->page_leftbar",
505 - "default.handlebars->container->topbar->1->1->MainMenuSpan->1->0->MainMenuMyDevices",
506 - "default.handlebars->container->column_l->p1->2->0"
474 + "player.htm->3->6"
475 ]
476 },
477 {
510 - "en": "My Account",
478 + "en": "eventslist.csv",
479 "xloc": [
512 - "default.handlebars->container->page_leftbar",
513 - "default.handlebars->container->topbar->1->1->MainMenuSpan->1->0->MainMenuMyAccount",
514 - "default.handlebars->container->column_l->p2->1",
515 - "default-mobile.handlebars->topMenu->3"
480 + "default.handlebars->13->1104",
481 + "default.handlebars->13->1109"
482 ]
483 },
484 {
519 - "en": "My Events",
485 + "en": "ERROR: Unable to add key.",
486 "xloc": [
521 - "default.handlebars->container->page_leftbar",
522 - "default.handlebars->container->topbar->1->1->MainMenuSpan->1->0->MainMenuMyEvents",
523 - "default.handlebars->container->column_l->p3->1"
487 + "default.handlebars->13->110"
488 ]
489 },
490 {
527 - "en": "My Files",
491 + "en": "1 day",
492 + "fr": "1 jour",
493 "xloc": [
529 - "default.handlebars->container->page_leftbar",
530 - "default.handlebars->container->topbar->1->1->MainMenuSpan->1->0->MainMenuMyFiles",
531 - "default.handlebars->container->column_l->p5->1",
532 - "default-mobile.handlebars->container->page_content->column_l->p5->1->1->0->5->1->1",
533 - "default-mobile.handlebars->topMenu->1"
494 + "default.handlebars->13->129",
495 + "default.handlebars->13->250",
496 + "default.handlebars->13->264"
497 ]
498 },
499 {
537 - "en": "My Users",
500 + "en": "Small Focus",
501 "xloc": [
539 - "default.handlebars->container->page_leftbar",
540 - "default.handlebars->container->topbar->1->1->MainMenuSpan->1->0->MainMenuMyUsers",
541 - "default.handlebars->container->column_l->p4->1"
502 + "default.handlebars->13->560"
503 ]
504 },
505 {
545 - "en": "My Server",
506 + "en": "Arabic (Tunisia)",
507 "xloc": [
547 - "default.handlebars->container->page_leftbar",
548 - "default.handlebars->container->topbar->1->1->MainMenuSpan->1->0->MainMenuMyServer",
549 - "default.handlebars->container->column_l->p6->3"
508 + "default.handlebars->13->681"
509 ]
510 },
511 {
553 - "en": "General",
512 + "en": "{0}b left",
513 "xloc": [
555 - "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDev",
556 - "default.handlebars->container->topbar->1->1->MeshSubMenuSpan->MeshSubMenu->1->0->MeshGeneral",
557 - "default.handlebars->container->topbar->1->1->UserSubMenuSpan->UserSubMenu->1->0->UserGeneral",
558 - "default.handlebars->container->topbar->1->1->ServerSubMenuSpan->ServerSubMenu->1->0->ServerGeneral"
514 + "default-mobile.handlebars->9->67"
515 ]
516 },
517 {
562 - "en": "Details",
518 + "en": "KernelDriver",
519 "xloc": [
564 - "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevInfo"
520 + "default.handlebars->13->572"
521 ]
522 },
523 {
568 - "en": "Intel® AMT",
524 + "en": "Tracing",
525 "xloc": [
570 - "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevAmt"
526 + "default.handlebars->container->column_l->p41->3->3"
527 ]
528 },
529 {
574 - "en": "Plugins",
530 + "en": "Connections",
531 "xloc": [
576 - "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevPlugins"
532 + "default.handlebars->container->column_l->p40->3->1->p40type->1"
533 ]
534 },
535 {
580 - "en": "Stats",
536 + "en": "Install local",
537 "xloc": [
582 - "default.handlebars->container->topbar->1->1->ServerSubMenuSpan->ServerSubMenu->1->0->ServerStats"
538 + "default.handlebars->13->957"
539 ]
540 },
541 {
586 - "en": "Trace",
542 + "en": "ESC",
543 "xloc": [
588 - "default.handlebars->container->topbar->1->1->ServerSubMenuSpan->ServerSubMenu->1->0->ServerTrace"
544 + "default.handlebars->container->column_l->p12->termTable->1->1->6->1->3"
545 ]
546 },
547 {
592 - "en": "Server disconnected",
548 + "en": "Change the power state of the remote machine",
549 "xloc": [
594 - "default.handlebars->container->column_l->p0->p0message->p0span",
595 - "default-mobile.handlebars->container->page_content->column_l->p0->1->p0message->p0span"
550 + "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
551 ]
552 },
553 {
599 - "en": ",",
554 + "en": "4.jQuery User Interface - MIT License",
555 "xloc": [
601 - "default.handlebars->container->column_l->p0->p0message",
602 - "default-mobile.handlebars->container->page_content->column_l->p0->1->p0message"
556 + "terms.handlebars->container->column_l->51->1->0",
557 + "terms-mobile.handlebars->container->page_content->column_l->51->1->0"
558 ]
559 },
560 {
606 - "en": "click to reconnect",
561 + "en": "* Leave blank to assign a random password to each device.",
562 "xloc": [
608 - "default.handlebars->container->column_l->p0->p0message->2->0",
609 - "default-mobile.handlebars->container->page_content->column_l->p0->1->p0message->2->0"
563 + "default.handlebars->13->996"
564 ]
565 },
566 {
613 - "en": ".",
567 + "en": "Mesh Agent",
568 "xloc": [
615 - "default.handlebars->container->column_l->p0->p0message",
616 - "default.handlebars->container->column_l->p1->NoMeshesPanel->1->1->0->3->getStarted1",
617 - "default-mobile.handlebars->container->page_content->column_l->p0->1->p0message",
618 - "login.handlebars->container->column_l->centralTable->1->0->logincell->loginpanel->1->resetAccountDiv",
619 - "login.handlebars->container->column_l->centralTable->1->0->logincell->loginpanel->1->newAccountDiv",
620 - "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->loginpanel->1->resetAccountDiv",
621 - "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->loginpanel->1->newAccountDiv",
622 - "terms.handlebars->container->column_l->75->1",
623 - "terms-mobile.handlebars->container->page_content->column_l->75->1"
569 + "default.handlebars->13->281",
570 + "default.handlebars->13->284",
571 + "default.handlebars->13->292",
572 + "default.handlebars->13->295",
573 + "default.handlebars->13->298",
574 + "default.handlebars->13->421",
575 + "default.handlebars->13->452",
576 + "default-mobile.handlebars->9->197"
577 ]
578 },
579 {
627 - "en": "Columns",
580 + "en": "Event List Export",
581 "xloc": [
629 - "default.handlebars->container->column_l->p1->devListToolbarViewIcons",
630 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarView->viewselect->1"
582 + "default.handlebars->13->1107"
583 ]
584 },
585 {
634 - "en": "List",
586 + "en": "{0} bytes remaining",
587 + "fr": "{0} octets restants",
588 "xloc": [
636 - "default.handlebars->container->column_l->p1->devListToolbarViewIcons",
637 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarView->viewselect->3"
589 + "default.handlebars->13->1069"
590 ]
591 },
592 {
641 - "en": "Desktops",
593 + "en": "Paste",
594 "xloc": [
643 - "default.handlebars->container->column_l->p1->devListToolbarViewIcons",
644 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarView->viewselect->5"
645 - ]
646 - },
595 + "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
596 + "default.handlebars->container->column_l->p12->termTable->1->1->6->1->3",
597 + "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
598 + "default.handlebars->13->595",
599 + "default.handlebars->13->618",
600 + "default.handlebars->13->1093",
601 + "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->3",
602 + "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->3",
603 + "default-mobile.handlebars->9->84",
604 + "default-mobile.handlebars->9->258"
605 + ]
606 + },
607 {
648 - "en": "Map",
608 + "en": ":",
609 "xloc": [
650 - "default.handlebars->container->column_l->p1->devListToolbarViewIcons",
651 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarView->viewselect->viewselectmapoption"
610 + "agentinvite.handlebars->3->23",
611 + "agentinvite.handlebars->3->38"
612 ]
613 },
614 {
655 - "en": "Group Action",
615 + "en": " node",
616 + "fr": "nœud",
617 "xloc": [
657 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar",
658 - "default.handlebars->13->348"
618 + "default.handlebars->13->303",
619 + "default-mobile.handlebars->9->124"
620 ]
621 },
622 {
662 - "en": "Filter",
623 + "en": "Traffic router used to connect to a device thru this server",
624 "xloc": [
664 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar",
665 - "default.handlebars->container->column_l->p4->3->1->0->3->3"
625 + "default.handlebars->13->477"
626 ]
627 },
628 {
669 - "en": "Show devices operating system name",
629 + "en": "Unlimited",
630 + "fr": "Illimité",
631 "xloc": [
671 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar->7"
632 + "default.handlebars->13->132",
633 + "default.handlebars->13->253",
634 + "default.handlebars->13->267"
635 ]
636 },
637 {
675 - "en": "OS Name",
638 + "en": "Confirm",
639 "xloc": [
677 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar->7->1"
640 + "default.handlebars->13->351",
641 + "default.handlebars->13->529",
642 + "default.handlebars->13->1001",
643 + "default-mobile.handlebars->9->217",
644 + "default-mobile.handlebars->9->285"
645 ]
646 },
647 {
681 - "en": "Connect All",
648 + "en": "Enable browser notification",
649 "xloc": [
683 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->kvmListToolbar->kvmMultiConnectButtonSpan"
650 + "messenger.handlebars->xtop"
651 ]
652 },
653 {
687 - "en": "Disconnect All",
654 + "en": "Toggle night mode",
655 + "fr": "Basculer mode nuit",
656 "xloc": [
689 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->kvmListToolbar"
657 + "agentinvite.handlebars->container->topbar->uiMenuButton->uiMenu",
658 + "default.handlebars->container->topbar->1->1->uiMenuButton->uiMenu",
659 + "error404.handlebars->container->topbar->uiMenuButton->uiMenu",
660 + "login.handlebars->container->topbar->uiMenuButton->uiMenu",
661 + "terms.handlebars->container->topbar->uiMenuButton->uiMenu"
662 ]
663 },
664 {
693 - "en": "Automatic connect",
665 + "en": "admin",
666 "xloc": [
695 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->kvmListToolbar->kvmAutoConnectButtonSpan->0"
667 + "default.handlebars->13->198"
668 ]
669 },
670 {
699 - "en": "Auto",
671 + "en": "(",
672 "xloc": [
701 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->kvmListToolbar->kvmAutoConnectButtonSpan->0",
702 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSizeDropDown->termSizeList->2"
673 + "default.handlebars->container->column_l->p2->p2createMeshLink1",
674 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3createMeshLink1"
675 ]
676 },
677 {
706 - "en": "Settings",
678 + "en": "Location",
679 "xloc": [
708 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->kvmListToolbar",
709 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea4->1->3"
680 + "default.handlebars->13->476"
681 ]
682 },
683 {
713 - "en": "Search Location",
684 + "en": ".",
685 "xloc": [
715 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devMapToolbar"
686 + "default.handlebars->container->column_l->p0->p0message",
687 + "default.handlebars->container->column_l->p1->NoMeshesPanel->1->1->0->3->getStarted1",
688 + "default-mobile.handlebars->container->page_content->column_l->p0->1->p0message",
689 + "login.handlebars->container->column_l->centralTable->1->0->logincell->loginpanel->1->resetAccountDiv",
690 + "login.handlebars->container->column_l->centralTable->1->0->logincell->loginpanel->1->newAccountDiv",
691 + "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->loginpanel->1->resetAccountDiv",
692 + "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->loginpanel->1->newAccountDiv",
693 + "terms.handlebars->container->column_l->75->1",
694 + "terms-mobile.handlebars->container->page_content->column_l->75->1"
695 ]
696 },
697 {
719 - "en": "Search",
698 + "en": ",",
699 "xloc": [
721 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devMapToolbar"
700 + "default.handlebars->container->column_l->p0->p0message",
701 + "default-mobile.handlebars->container->page_content->column_l->p0->1->p0message"
702 ]
703 },
704 {
725 - "en": "Search for location",
705 + "en": "-",
706 "xloc": [
727 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devMapToolbar"
707 + "default-mobile.handlebars->9->228"
708 ]
709 },
710 {
731 - "en": "Reset",
711 + "en": "TLS security required",
712 + "fr": "Sécurité TLS requise",
713 "xloc": [
733 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devMapToolbar",
734 - "default.handlebars->13->505",
735 - "default-mobile.handlebars->9->205"
714 + "default.handlebars->13->202",
715 + "default.handlebars->13->517",
716 + "default-mobile.handlebars->9->213"
717 ]
718 },
719 {
739 - "en": "Reset map view",
720 + "en": "Scan",
721 "xloc": [
741 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devMapToolbar"
722 + "default.handlebars->13->211"
723 ]
724 },
725 {
745 - "en": "View",
726 + "en": " and authenticate to the server using this username and password.",
727 + "fr": "et authentifiez-vous sur le serveur en utilisant ce nom d'utilisateur et mot de passe.",
728 "xloc": [
747 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarView"
729 + "default.handlebars->13->222"
730 ]
731 },
732 {
751 - "en": "Sort",
733 + "en": "Multi-Desktop",
734 "xloc": [
753 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSort"
735 + "default.handlebars->contextMenu->cxmdesktop"
736 ]
737 },
738 {
757 - "en": "Group",
739 + "en": "{0} megabytes remaining",
740 "xloc": [
759 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSort->sortselect->1",
760 - "default.handlebars->13->381",
761 - "default-mobile.handlebars->9->131"
741 + "default.handlebars->13->1071"
742 ]
743 },
744 {
765 - "en": "Power",
745 + "en": "Manager",
746 "xloc": [
767 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSort->sortselect->3"
747 + "default.handlebars->13->1128"
748 ]
749 },
750 {
771 - "en": "Device",
751 + "en": "Linux / BSD (UnInstall)",
752 "xloc": [
773 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSort->sortselect->5"
753 + "default.handlebars->13->275"
754 ]
755 },
756 {
777 - "en": "Tags",
757 + "en": "Device is in powered off state (S5).",
758 "xloc": [
779 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSort->sortselect->7",
780 - "default.handlebars->13->548",
781 - "default-mobile.handlebars->9->194",
782 - "default-mobile.handlebars->9->195",
783 - "default-mobile.handlebars->9->222"
759 + "default.handlebars->13->315"
760 ]
761 },
762 {
787 - "en": "Size",
763 + "en": "Generate New Tokens",
764 "xloc": [
789 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSize"
765 + "default.handlebars->13->96"
766 ]
767 },
768 {
793 - "en": "Small",
769 + "en": "Confirm delete selected devices(s)?",
770 "xloc": [
795 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSize->sizeselect->1"
771 + "default.handlebars->13->350"
772 ]
773 },
774 {
799 - "en": "Medium",
775 + "en": "Router",
776 "xloc": [
801 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSize->sizeselect->3",
802 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->7->d7framelimiter->3",
803 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->7->d7framelimiter->3"
777 + "default.handlebars->13->167",
778 + "default.handlebars->13->478"
779 ]
780 },
781 {
807 - "en": "Large",
782 + "en": "Sleeping",
783 "xloc": [
809 - "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSize->sizeselect->5"
784 + "default.handlebars->13->308",
785 + "default.handlebars->13->310",
786 + "default-mobile.handlebars->9->105",
787 + "default-mobile.handlebars->9->106"
788 ]
789 },
790 {
813 - "en": "To get started,",
791 + "en": "Edit Intel&reg; AMT credentials",
792 "xloc": [
815 - "default.handlebars->container->column_l->p1->NoMeshesPanel->1->1->0->3->getStarted1"
793 + "default.handlebars->13->434",
794 + "default.handlebars->13->437",
795 + "default.handlebars->13->518",
796 + "default-mobile.handlebars->9->214"
797 ]
798 },
799 {
819 - "en": "click here to create a device group",
800 + "en": "Device connections.",
801 "xloc": [
821 - "default.handlebars->container->column_l->p1->NoMeshesPanel->1->1->0->3->getStarted1->1->0"
802 + "default.handlebars->13->865"
803 ]
804 },
805 {
825 - "en": "No device groups.",
806 + "en": "Please contact the site administrator for terms of use.",
807 "xloc": [
827 - "default.handlebars->container->column_l->p1->NoMeshesPanel->1->1->0->3->getStarted2",
828 - "default.handlebars->container->column_l->p2->p2noMeshFound",
829 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3noMeshFound"
808 + "terms.handlebars->container->column_l->3",
809 + "terms-mobile.handlebars->container->page_content->column_l->3"
810 ]
811 },
812 {
833 - "en": "X",
813 + "en": "Linux ARM",
814 "xloc": [
835 - "default.handlebars->container->column_l->p1->xdevicesmap->xmapSearchResultsDlg->xmapSearchResultsBck->xmapSearchClose->0",
836 - "default-mobile.handlebars->dialog->1->id_dialogclose->0",
837 - "login.handlebars->dialog->dialogHeader->id_dialogclose->0",
838 - "login-mobile.handlebars->dialog->1->id_dialogclose->0"
815 + "default.handlebars->13->400",
816 + "default-mobile.handlebars->9->150"
817 ]
818 },
819 {
842 - "en": "Location Results",
820 + "en": "Spanish (Ecuador)",
821 "xloc": [
844 - "default.handlebars->container->column_l->p1->xdevicesmap->xmapSearchResultsDlg->xmapSearchResultsBck->3"
822 + "default.handlebars->13->823"
823 ]
824 },
825 {
848 - "en": "Account security",
826 + "en": "Sami (Lappish)",
827 "xloc": [
850 - "default.handlebars->container->column_l->p2->p2AccountSecurity->1->0"
828 + "default.handlebars->13->805"
829 ]
830 },
831 {
854 - "en": "✓",
832 + "en": "Gaelic (Scots)",
833 "xloc": [
856 - "default.handlebars->container->column_l->p2->p2AccountSecurity->3->manageAuthApp->0->authAppSetupCheck->0",
857 - "default.handlebars->container->column_l->p2->p2AccountSecurity->3->manageHardwareOtp->0->authKeySetupCheck->0",
858 - "default.handlebars->container->column_l->p2->p2AccountSecurity->3->manageOtp->0->authCodesSetupCheck->0",
859 - "default.handlebars->container->column_l->p5->p5filetable->bigok->0",
860 - "default.handlebars->container->column_l->p13->p13filetable->p13bigok->0",
861 - "player.htm->p11->deskarea0->deskarea3x->bigok->0"
834 + "default.handlebars->13->740"
835 ]
836 },
837 {
865 - "en": "Manage authenticator app",
838 + "en": "Device Groups",
839 "xloc": [
867 - "default.handlebars->container->column_l->p2->p2AccountSecurity->3->manageAuthApp->1->0",
868 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->3->manageAuthApp->0"
840 + "default.handlebars->container->column_l->p2->9",
841 + "default.handlebars->13->1201",
842 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->3"
843 ]
844 },
845 {
872 - "en": "Manage security keys",
846 + "en": "MacOS (64bit)",
847 "xloc": [
874 - "default.handlebars->container->column_l->p2->p2AccountSecurity->3->manageHardwareOtp->1->0"
848 + "default.handlebars->13->540"
849 ]
850 },
851 {
878 - "en": "Manage backup codes",
852 + "en": "My Users",
853 "xloc": [
880 - "default.handlebars->container->column_l->p2->p2AccountSecurity->3->manageOtp->1->0",
881 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->3->manageOtp->0"
854 + "default.handlebars->container->page_leftbar",
855 + "default.handlebars->container->topbar->1->1->MainMenuSpan->1->0->MainMenuMyUsers",
856 + "default.handlebars->container->column_l->p4->1"
857 ]
858 },
859 {
885 - "en": "Account actions",
860 + "en": "View notes about this user",
861 "xloc": [
887 - "default.handlebars->container->column_l->p2->p2AccountActions->1->0"
862 + "default.handlebars->13->1210"
863 ]
864 },
865 {
891 - "en": "Verify email",
866 + "en": "Share a file",
867 "xloc": [
893 - "default.handlebars->container->column_l->p2->p2AccountActions->3->verifyEmailId->0",
894 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->7->1->verifyEmailId->0"
868 + "messenger.handlebars->xtop"
869 ]
870 },
871 {
898 - "en": "Enable web notifications",
872 + "en": "Duration",
873 "xloc": [
900 - "default.handlebars->container->column_l->p2->p2AccountActions->3->accountEnableNotificationsSpan->0"
874 + "player.htm->3->2"
875 ]
876 },
877 {
904 - "en": "Localization Settings",
878 + "en": "{0} lower case",
879 "xloc": [
906 - "default.handlebars->container->column_l->p2->p2AccountActions->3->5",
907 - "default.handlebars->13->863"
880 + "login.handlebars->5->15",
881 + "login-mobile.handlebars->5->15"
882 ]
883 },
884 {
911 - "en": "Notification Settings",
885 + "en": "Italian (Standard)",
886 "xloc": [
913 - "default.handlebars->container->column_l->p2->p2AccountActions->3->8",
914 - "default.handlebars->13->868",
915 - "default.handlebars->13->1064"
887 + "default.handlebars->13->760"
888 ]
889 },
890 {
919 - "en": "Change email address",
891 + "en": "Good",
892 "xloc": [
921 - "default.handlebars->container->column_l->p2->p2AccountActions->3->accountChangeEmailAddressSpan->0",
922 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->7->3->changeEmailId->0"
893 + "default.handlebars->13->902"
894 ]
895 },
896 {
926 - "en": "Change password",
897 + "en": "Hostname Sync",
898 "xloc": [
928 - "default.handlebars->container->column_l->p2->p2AccountActions->3->13",
929 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->7->5->0"
899 + "default.handlebars->13->925"
900 ]
901 },
902 {
933 - "en": "Delete account",
903 + "en": "Connected.",
904 "xloc": [
935 - "default.handlebars->container->column_l->p2->p2AccountActions->3->17",
936 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->7->7->0"
905 + "messenger.handlebars->13->7"
906 ]
907 },
908 {
940 - "en": "Device Groups",
909 + "en": "Holding 1 entrie for copy",
910 "xloc": [
942 - "default.handlebars->container->column_l->p2->9",
943 - "default.handlebars->13->1201",
944 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->3"
911 + "default.handlebars->13->621",
912 + "default-mobile.handlebars->9->261"
913 ]
914 },
915 {
948 - "en": "(",
916 + "en": "Use the desktop version of this website to add devices.",
917 "xloc": [
950 - "default.handlebars->container->column_l->p2->p2createMeshLink1",
951 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3createMeshLink1"
918 + "default-mobile.handlebars->9->96"
919 ]
920 },
921 {
955 - "en": "New",
922 + "en": "✓",
923 "xloc": [
957 - "default.handlebars->container->column_l->p2->p2createMeshLink1->1",
958 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3createMeshLink1->1"
924 + "default.handlebars->container->column_l->p2->p2AccountSecurity->3->manageAuthApp->0->authAppSetupCheck->0",
925 + "default.handlebars->container->column_l->p2->p2AccountSecurity->3->manageHardwareOtp->0->authKeySetupCheck->0",
926 + "default.handlebars->container->column_l->p2->p2AccountSecurity->3->manageOtp->0->authCodesSetupCheck->0",
927 + "default.handlebars->container->column_l->p5->p5filetable->bigok->0",
928 + "default.handlebars->container->column_l->p13->p13filetable->p13bigok->0",
929 + "player.htm->p11->deskarea0->deskarea3x->bigok->0"
930 ]
931 },
932 {
962 - "en": ")",
933 + "en": "Intel AMT CIRA disconnected",
934 "xloc": [
964 - "default.handlebars->container->column_l->p2->p2createMeshLink1",
965 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3createMeshLink1"
935 + "default.handlebars->13->121"
936 ]
937 },
938 {
969 - "en": "Get started here!",
939 + "en": "Invalid JSON file: {0}.",
940 "xloc": [
971 - "default.handlebars->container->column_l->p2->p2noMeshFound->p2createMeshLink2->1->0",
972 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3noMeshFound->p3createMeshLink2->1->0"
941 + "default.handlebars->13->1135"
942 ]
943 },
944 {
976 - "en": "Show",
945 + "en": "Access Denied",
946 + "fr": "Accès refusé",
947 "xloc": [
978 - "default.handlebars->container->column_l->p3->3->1->0->3",
979 - "default.handlebars->container->column_l->p16->3->1->0->5",
980 - "default.handlebars->container->column_l->p31->5->1->0->5",
981 - "default.handlebars->container->column_l->p41->3->1"
948 + "default.handlebars->13->638"
949 ]
950 },
951 {
985 - "en": "Last 60",
952 + "en": "Manage Device Group Users",
953 "xloc": [
987 - "default.handlebars->container->column_l->p3->3->1->0->3->p3limitdropdown->1",
988 - "default.handlebars->container->column_l->p16->3->1->0->5->p16limitdropdown->1",
989 - "default.handlebars->container->column_l->p31->5->1->0->5->p31limitdropdown->1"
954 + "default.handlebars->13->1024",
955 + "default.handlebars->13->1042",
956 + "default-mobile.handlebars->9->292",
957 + "default-mobile.handlebars->9->309"
958 ]
959 },
960 {
993 - "en": "Last 120",
961 + "en": "Edit Device Group Features",
962 "xloc": [
995 - "default.handlebars->container->column_l->p3->3->1->0->3->p3limitdropdown->3",
996 - "default.handlebars->container->column_l->p16->3->1->0->5->p16limitdropdown->3",
997 - "default.handlebars->container->column_l->p31->5->1->0->5->p31limitdropdown->3"
963 + "default.handlebars->13->1017"
964 ]
965 },
966 {
1001 - "en": "Last 250",
967 + "en": "{0} upper case",
968 "xloc": [
1003 - "default.handlebars->container->column_l->p3->3->1->0->3->p3limitdropdown->5",
1004 - "default.handlebars->container->column_l->p16->3->1->0->5->p16limitdropdown->5",
1005 - "default.handlebars->container->column_l->p31->5->1->0->5->p31limitdropdown->5",
1006 - "default.handlebars->container->column_l->p41->3->1->p41limitdropdown->3"
969 + "login.handlebars->5->14",
970 + "login-mobile.handlebars->5->14"
971 ]
972 },
973 {
1010 - "en": "Last 500",
974 + "en": "Danish",
975 "xloc": [
1012 - "default.handlebars->container->column_l->p3->3->1->0->3->p3limitdropdown->7",
1013 - "default.handlebars->container->column_l->p16->3->1->0->5->p16limitdropdown->7",
1014 - "default.handlebars->container->column_l->p31->5->1->0->5->p31limitdropdown->7",
1015 - "default.handlebars->container->column_l->p41->3->1->p41limitdropdown->5"
976 + "default.handlebars->13->709"
977 ]
978 },
979 {
1019 - "en": "Last 1000",
980 + "en": "No Events Found",
981 "xloc": [
1021 - "default.handlebars->container->column_l->p3->3->1->0->3->p3limitdropdown->9",
1022 - "default.handlebars->container->column_l->p16->3->1->0->5->p16limitdropdown->9",
1023 - "default.handlebars->container->column_l->p31->5->1->0->5->p31limitdropdown->9",
1024 - "default.handlebars->container->column_l->p41->3->1->p41limitdropdown->7"
982 + "default.handlebars->13->632",
983 + "default.handlebars->13->1101",
984 + "default.handlebars->13->1226"
985 ]
986 },
987 {
1028 - "en": "Download Events",
988 + "en": "Italian (Switzerland)",
989 "xloc": [
1030 - "default.handlebars->container->column_l->p3->3->1->0->3->3",
1031 - "default.handlebars->container->column_l->p16->3->1->0->5->3",
1032 - "default.handlebars->container->column_l->p31->5->1->0->5->3"
990 + "default.handlebars->13->761"
991 ]
992 },
993 {
1036 - "en": "Broadcast",
994 + "en": "ERROR: ",
995 "xloc": [
1038 - "default.handlebars->container->column_l->p4->3->1->0->3->1"
996 + "default.handlebars->13->114"
997 ]
998 },
999 {
1042 - "en": "Download user information",
1000 + "en": "General -",
1001 "xloc": [
1044 - "default.handlebars->container->column_l->p4->3->1->0->3->1->3"
1002 + "default.handlebars->container->column_l->p10->1->1->0->1->p10title->3",
1003 + "default.handlebars->container->column_l->p20->5",
1004 + "default.handlebars->container->column_l->p30->1->1->0->1->p30title->3"
1005 ]
1006 },
1007 {
1048 - "en": "Batch create many user accounts",
1008 + "en": "Log In",
1009 "xloc": [
1050 - "default.handlebars->container->column_l->p4->3->1->0->3->1->5"
1010 + "login.handlebars->container->column_l->centralTable->1->0->logincell->loginpanel->1->5->1",
1011 + "login.handlebars->container->column_l->centralTable->1->0->logincell->loginpanel->1->7->1->4->3",
1012 + "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->loginpanel->1->5->1",
1013 + "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->loginpanel->1->7->1->4->3"
1014 ]
1015 },
1016 {
1054 - "en": "New Account...",
1017 + "en": "Linux only",
1018 "xloc": [
1056 - "default.handlebars->container->column_l->p4->3->1->0->3->3"
1019 + "default.handlebars->13->246"
1020 ]
1021 },
1022 {
1060 - "en": "Up",
1023 + "en": "Group Action",
1024 "xloc": [
1062 - "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
1063 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
1064 - "default.handlebars->container->dialog->dialogBody->dialog3->d3servermode->d3serveraction",
1065 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->1",
1066 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->1"
1025 + "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar",
1026 + "default.handlebars->13->348"
1027 ]
1028 },
1029 {
1070 - "en": "Rename",
1030 + "en": "Get MQTT login credentials for this device.",
1031 "xloc": [
1072 - "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
1073 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
1074 - "default.handlebars->13->610",
1075 - "default.handlebars->13->1090",
1076 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->1",
1077 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->1",
1078 - "default-mobile.handlebars->9->81",
1079 - "default-mobile.handlebars->9->250"
1032 + "default.handlebars->13->485"
1033 ]
1034 },
1035 {
1083 - "en": "Delete",
1036 + "en": "Arabic (Oman)",
1037 "xloc": [
1085 - "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
1086 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
1087 - "default.handlebars->container->dialog->idx_dlgButtonBar->5",
1088 - "default.handlebars->13->607",
1089 - "default.handlebars->13->1087",
1090 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->1",
1091 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->1",
1092 - "default-mobile.handlebars->9->78",
1093 - "default-mobile.handlebars->9->247",
1094 - "player.htm->p11->dialog->idx_dlgButtonBar->5"
1038 + "default.handlebars->13->677"
1039 ]
1040 },
1041 {
1098 - "en": "New Folder",
1042 + "en": "Recursive delete",
1043 "xloc": [
1100 - "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
1101 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
1102 - "default.handlebars->13->604",
1103 - "default.handlebars->13->1085",
1104 - "default-mobile.handlebars->9->76",
1105 - "default-mobile.handlebars->9->244"
1044 + "default.handlebars->13->605",
1045 + "default.handlebars->13->1086",
1046 + "default-mobile.handlebars->9->77",
1047 + "default-mobile.handlebars->9->245"
1048 ]
1049 },
1050 {
1109 - "en": "Upload",
1051 + "en": "Strong",
1052 "xloc": [
1111 - "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
1112 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
1113 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->3",
1114 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->3"
1053 + "default.handlebars->13->901"
1054 ]
1055 },
1056 {
1118 - "en": "Cut",
1057 + "en": "User Consent",
1058 "xloc": [
1120 - "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
1121 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
1122 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->3",
1123 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->3"
1059 + "default.handlebars->13->939"
1060 ]
1061 },
1062 {
1127 - "en": "Copy",
1063 + "en": "<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.",
1064 "xloc": [
1129 - "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
1130 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
1131 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->3",
1132 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->3"
1065 + "default-mobile.handlebars->9->17"
1066 ]
1067 },
1068 {
1136 - "en": "Paste",
1069 + "en": "Intel&reg; ME",
1070 "xloc": [
1138 - "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
1139 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->3",
1140 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
1141 - "default.handlebars->13->595",
1142 - "default.handlebars->13->618",
1143 - "default.handlebars->13->1093",
1144 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->3",
1145 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->3",
1146 - "default-mobile.handlebars->9->84",
1147 - "default-mobile.handlebars->9->258"
1071 + "default.handlebars->13->438",
1072 + "default-mobile.handlebars->9->183"
1073 ]
1074 },
1075 {
1151 - "en": "Sort by name",
1076 + "en": "Any supported",
1077 "xloc": [
1153 - "default.handlebars->container->column_l->p5->p5toolbar->1->2->p5filesubhead->1->p5sortdropdown->1",
1154 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsArea->DeskToolsProcessTab->deskToolsHeader",
1155 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsArea->DeskToolsServiceTab->deskToolsServiceHeader",
1156 - "default.handlebars->container->column_l->p13->p13toolbar->1->4->1->1->p13sortdropdown->1",
1157 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->2->1->1->1->0->3->p5sortdropdown->1",
1158 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->4->1->1->1->0->3->p13sortdropdown->1"
1078 + "default.handlebars->13->243"
1079 ]
1080 },
1081 {
1162 - "en": "Sort by size",
1082 + "en": "Chinese (PRC)",
1083 "xloc": [
1164 - "default.handlebars->container->column_l->p5->p5toolbar->1->2->p5filesubhead->1->p5sortdropdown->3",
1165 - "default.handlebars->container->column_l->p13->p13toolbar->1->4->1->1->p13sortdropdown->3",
1166 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->2->1->1->1->0->3->p5sortdropdown->3",
1167 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->4->1->1->1->0->3->p13sortdropdown->3"
1084 + "default.handlebars->13->701"
1085 ]
1086 },
1087 {
1171 - "en": "Sort by date",
1088 + "en": "Delete Account",
1089 "xloc": [
1173 - "default.handlebars->container->column_l->p5->p5toolbar->1->2->p5filesubhead->1->p5sortdropdown->5",
1174 - "default.handlebars->container->column_l->p13->p13toolbar->1->4->1->1->p13sortdropdown->5",
1175 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->2->1->1->1->0->3->p5sortdropdown->5",
1176 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->4->1->1->1->0->3->p13sortdropdown->5"
1090 + "default.handlebars->13->877",
1091 + "default-mobile.handlebars->9->40"
1092 ]
1093 },
1094 {
1180 - "en": "Descend by name",
1095 + "en": "Edit Notes",
1096 "xloc": [
1182 - "default.handlebars->container->column_l->p5->p5toolbar->1->2->p5filesubhead->1->p5sortdropdown->7",
1183 - "default.handlebars->container->column_l->p13->p13toolbar->1->4->1->1->p13sortdropdown->7",
1184 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->2->1->1->1->0->3->p5sortdropdown->7",
1185 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->4->1->1->1->0->3->p13sortdropdown->7"
1097 + "default.handlebars->13->1048",
1098 + "default-mobile.handlebars->9->315"
1099 ]
1100 },
1101 {
1189 - "en": "Descend by size",
1102 + "en": "Forgot user/password?",
1103 "xloc": [
1191 - "default.handlebars->container->column_l->p5->p5toolbar->1->2->p5filesubhead->1->p5sortdropdown->9",
1192 - "default.handlebars->container->column_l->p13->p13toolbar->1->4->1->1->p13sortdropdown->9",
1193 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->2->1->1->1->0->3->p5sortdropdown->9",
1194 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->4->1->1->1->0->3->p13sortdropdown->9"
1104 + "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->loginpanel->1->resetAccountDiv->resetAccountSpan"
1105 ]
1106 },
1107 {
1198 - "en": "Descend by date",
1108 + "en": "Upload File",
1109 "xloc": [
1200 - "default.handlebars->container->column_l->p5->p5toolbar->1->2->p5filesubhead->1->p5sortdropdown->11",
1201 - "default.handlebars->container->column_l->p13->p13toolbar->1->4->1->1->p13sortdropdown->11",
1202 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->2->1->1->1->0->3->p5sortdropdown->11",
1203 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->4->1->1->1->0->3->p13sortdropdown->11"
1110 + "default.handlebars->container->dialog->dialogBody->dialog3->d3localmode->1",
1111 + "default.handlebars->13->611",
1112 + "default.handlebars->13->628",
1113 + "default.handlebars->13->630",
1114 + "default.handlebars->13->1091",
1115 + "default.handlebars->13->1098",
1116 + "default-mobile.handlebars->9->82",
1117 + "default-mobile.handlebars->9->251",
1118 + "default-mobile.handlebars->9->269"
1119 ]
1120 },
1121 {
1207 - "en": "These files are shared publicly, click \"link\" to get public url.",
1122 + "en": "New Tokens",
1123 "xloc": [
1209 - "default.handlebars->container->column_l->p5->p5filetable->p5PublicShare->0"
1124 + "default-mobile.handlebars->9->24"
1125 ]
1126 },
1127 {
1213 - "en": "✗",
1128 + "en": "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://",
1129 "xloc": [
1215 - "default.handlebars->container->column_l->p5->p5filetable->bigfail->0",
1216 - "default.handlebars->container->column_l->p13->p13filetable->p13bigfail->0",
1217 - "player.htm->p11->deskarea0->deskarea3x->bigfail->0"
1130 + "agentinvite.handlebars->3->33"
1131 ]
1132 },
1133 {
1221 - "en": "Server actions",
1134 + "en": "Persian/Iran",
1135 "xloc": [
1223 - "default.handlebars->container->column_l->p6->p2ServerActions->1->0"
1136 + "default.handlebars->13->792"
1137 ]
1138 },
1139 {
1227 - "en": "Download server backup",
1140 + "en": "Connection closed.",
1141 "xloc": [
1229 - "default.handlebars->container->column_l->p6->p2ServerActions->3->p2ServerActionsBackup->0"
1142 + "messenger.handlebars->13->3"
1143 ]
1144 },
1145 {
1233 - "en": "Restore server with backup",
1146 + "en": "Win+Up",
1147 "xloc": [
1235 - "default.handlebars->container->column_l->p6->p2ServerActions->3->p2ServerActionsRestore->0"
1148 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->7",
1149 + "default-mobile.handlebars->dialog->3->dialog3->deskkeys->9"
1150 ]
1151 },
1152 {
1239 - "en": "Check server version",
1153 + "en": "Save...",
1154 "xloc": [
1241 - "default.handlebars->container->column_l->p6->p2ServerActions->3->p2ServerActionsVersion->0"
1155 + "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1156 ]
1157 },
1158 {
1245 - "en": "Show server error log",
1159 + "en": "German (Liechtenstein)",
1160 "xloc": [
1247 - "default.handlebars->container->column_l->p6->p2ServerActions->3->p2ServerActionsErrors->0"
1161 + "default.handlebars->13->747"
1162 ]
1163 },
1164 {
1251 - "en": "Server Statistics",
1165 + "en": "Please wait a few minute to receive the verification.",
1166 "xloc": [
1253 - "default.handlebars->container->column_l->p6->8"
1167 + "default.handlebars->13->870",
1168 + "default-mobile.handlebars->9->32"
1169 ]
1170 },
1171 {
1257 - "en": "Back",
1172 + "en": "Win+Down",
1173 "xloc": [
1259 - "default.handlebars->container->column_l->p10->1->1->0->1->p10title->p10BackButton",
1260 - "default.handlebars->container->column_l->p11->p11title->p11deviceNameHeader->p11BackButton",
1261 - "default.handlebars->container->column_l->p12->p12title->p12BackButton",
1262 - "default.handlebars->container->column_l->p13->p13title->p13BackButton",
1263 - "default.handlebars->container->column_l->p14->p14title->p14BackButton",
1264 - "default.handlebars->container->column_l->p15->p15title->p15BackButton",
1265 - "default.handlebars->container->column_l->p16->p16title->p16BackButton",
1266 - "default.handlebars->container->column_l->p17->p17title->p17BackButton",
1267 - "default.handlebars->container->column_l->p20->3",
1268 - "default.handlebars->container->column_l->p30->1->1->0->1->p30title->1",
1269 - "default.handlebars->container->column_l->p31->1",
1270 - "error404.handlebars->container->footer->1->1->0->3->0",
1271 - "terms.handlebars->container->footer->1->1->0->3->0",
1272 - "terms-mobile.handlebars->container->footer->1->1->0->3->1"
1174 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->5",
1175 + "default-mobile.handlebars->dialog->3->dialog3->deskkeys->7"
1176 ]
1177 },
1178 {
1276 - "en": "General -",
1179 + "en": "Interfaces",
1180 + "xloc": [
1181 + "default.handlebars->13->474"
1182 + ]
1183 + },
1184 + {
1185 + "en": "Start",
1186 "xloc": [
1278 - "default.handlebars->container->column_l->p10->1->1->0->1->p10title->3",
1279 - "default.handlebars->container->column_l->p20->5",
1280 - "default.handlebars->container->column_l->p30->1->1->0->1->p30title->3"
1187 + "default.handlebars->13->577"
1188 ]
1189 },
1190 {
1284 - "en": "Full Screen. Hold shift to browser full screen.",
1191 + "en": "Click here to edit the server-side device name",
1192 "xloc": [
1286 - "default.handlebars->container->column_l->p11->p11title->p11deviceNameHeader->devListToolbarViewIcons",
1287 - "default.handlebars->container->column_l->p14->p14title->devListToolbarViewIcons"
1193 + "default.handlebars->13->378"
1194 ]
1195 },
1196 {
1291 - "en": "Desktop -",
1197 + "en": "Scanning...",
1198 "xloc": [
1293 - "default.handlebars->container->column_l->p11->p11title->p11deviceNameHeader->5"
1199 + "default.handlebars->13->213"
1200 ]
1201 },
1202 {
1297 - "en": "Intel® AMT Redirection port or KVM feature is disabled",
1203 + "en": "Punjabi",
1204 "xloc": [
1299 - "default.handlebars->container->column_l->p11->p11warning->3",
1300 - "default.handlebars->container->column_l->p12->p12warning->3"
1205 + "default.handlebars->13->796"
1206 ]
1207 },
1208 {
1304 - "en": ", click here to enable it.",
1209 + "en": "Download MeshCentral Router, a TCP port mapping tool.",
1210 "xloc": [
1306 - "default.handlebars->container->column_l->p11->p11warning->3->p11warninga",
1307 - "default.handlebars->container->column_l->p12->p12warning->3->p12warninga"
1211 + "default.handlebars->13->166"
1212 ]
1213 },
1214 {
1311 - "en": "Remote computer is not powered on, click here to issue a power command.",
1215 + "en": "Linux NoKVM x86-64bit",
1216 "xloc": [
1313 - "default.handlebars->container->column_l->p11->p11warning2->3",
1314 - "default.handlebars->container->column_l->p12->p12warning2->3"
1217 + "default.handlebars->13->410",
1218 + "default-mobile.handlebars->9->160"
1219 ]
1220 },
1221 {
1318 - "en": "Toggle View Mode",
1222 + "en": "Zoom-out to extent",
1223 "xloc": [
1320 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1",
1321 - "player.htm->p11->deskarea0->deskarea1->1"
1224 + "default.handlebars->13->361",
1225 + "default.handlebars->13->368"
1226 ]
1227 },
1228 {
1325 - "en": "⇲",
1229 + "en": "Khmer",
1230 "xloc": [
1327 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1->3",
1328 - "player.htm->p11->deskarea0->deskarea1->1->1"
1231 + "default.handlebars->13->766"
1232 ]
1233 },
1234 {
1332 - "en": "Rotate Left",
1235 + "en": "Normal Connect",
1236 "xloc": [
1334 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1237 + "default.handlebars->termShellContextMenu->cxtermnorm"
1238 ]
1239 },
1240 {
1338 - "en": "↺",
1241 + "en": "Localization Settings",
1242 "xloc": [
1340 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1->5"
1243 + "default.handlebars->container->column_l->p2->p2AccountActions->3->5",
1244 + "default.handlebars->13->863"
1245 ]
1246 },
1247 {
1344 - "en": "Rotate Right",
1248 + "en": "Intel® AMT",
1249 "xloc": [
1346 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1250 + "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevAmt"
1251 ]
1252 },
1253 {
1350 - "en": "↻",
1254 + "en": "No devices in this group",
1255 "xloc": [
1352 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1->7"
1256 + "default-mobile.handlebars->9->94"
1257 ]
1258 },
1259 {
1356 - "en": "Server is recording this session",
1260 + "en": "Android ARM",
1261 "xloc": [
1358 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1",
1359 - "default.handlebars->container->column_l->p12->termTable->1->1->0->1->1",
1360 - "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->1"
1262 + "default.handlebars->13->399",
1263 + "default-mobile.handlebars->9->149"
1264 ]
1265 },
1266 {
1364 - "en": "Focus All",
1267 + "en": "Asturian",
1268 "xloc": [
1366 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1269 + "default.handlebars->13->687"
1270 ]
1271 },
1272 {
1370 - "en": "Toggle focus mode, when active only the region around the mouse is updated",
1273 + "en": "No information for this device.",
1274 "xloc": [
1372 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1275 + "default.handlebars->13->26"
1276 ]
1277 },
1278 {
1376 - "en": "Save...",
1279 + "en": "Arabic (Lebanon)",
1280 "xloc": [
1378 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1281 + "default.handlebars->13->674"
1282 ]
1283 },
1284 {
1382 - "en": "Save a screenshot of the remote desktop",
1285 + "en": "During activation, the agent will have access to admin password infomation.",
1286 "xloc": [
1384 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1287 + "default.handlebars->13->999"
1288 ]
1289 },
1290 {
1388 - "en": "Actions",
1291 + "en": "Spanish",
1292 "xloc": [
1390 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1",
1391 - "default.handlebars->container->column_l->p12->termTable->1->1->0->1->1",
1392 - "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->1",
1393 - "default.handlebars->13->463",
1394 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea4->1->3",
1395 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->0->1->1"
1293 + "default.handlebars->13->816"
1294 ]
1295 },
1296 {
1399 - "en": "Perform power actions on the device",
1297 + "en": "Greek",
1298 "xloc": [
1401 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1",
1402 - "default.handlebars->container->column_l->p12->termTable->1->1->0->1->1",
1403 - "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->1",
1404 - "default.handlebars->13->464"
1299 + "default.handlebars->13->750"
1300 ]
1301 },
1302 {
1408 - "en": "Settings...",
1303 + "en": "Get started here!",
1304 "xloc": [
1410 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1305 + "default.handlebars->container->column_l->p2->p2noMeshFound->p2createMeshLink2->1->0",
1306 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3noMeshFound->p3createMeshLink2->1->0"
1307 ]
1308 },
1309 {
1414 - "en": "Edit remote desktop settings",
1310 + "en": "Download MeshCmd, a command line tool that performs many functions.",
1311 "xloc": [
1416 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1312 + "default.handlebars->13->164"
1313 ]
1314 },
1315 {
1420 - "en": "Power Actions...",
1316 + "en": "1 group",
1317 + "fr": "1 groupe",
1318 "xloc": [
1422 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1",
1423 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea4->1->3"
1319 + "default.handlebars->13->1199"
1320 ]
1321 },
1322 {
1427 - "en": "Change the power state of the remote machine",
1323 + "en": "Toggle mouse and keyboard input",
1324 + "fr": "Basculer la souris et le clavier",
1325 "xloc": [
1429 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1326 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->9"
1327 ]
1328 },
1329 {
1433 - "en": "✖",
1330 + "en": "Admin Realms",
1331 "xloc": [
1435 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->3->idx_deskFullBtn2",
1436 - "default.handlebars->container->dialog->dialogHeader->id_dialogclose",
1437 - "player.htm->p11->dialog->dialogHeader->id_dialogclose"
1332 + "default.handlebars->13->1203"
1333 ]
1334 },
1335 {
1441 - "en": "AutoConnect",
1336 + "en": "Download Events",
1337 "xloc": [
1443 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->3",
1444 - "default.handlebars->container->column_l->p12->termTable->1->1->0->1->3",
1445 - "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->3",
1446 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->0->1->3"
1338 + "default.handlebars->container->column_l->p3->3->1->0->3->3",
1339 + "default.handlebars->container->column_l->p16->3->1->0->5->3",
1340 + "default.handlebars->container->column_l->p31->5->1->0->5->3"
1341 ]
1342 },
1343 {
1450 - "en": "Connect",
1344 + "en": " - Reset in {0} minute{1}.",
1345 + "fr": "- Réinitialisation en {0} minute {1}.",
1346 "xloc": [
1452 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->3->connectbutton1span",
1453 - "default.handlebars->container->column_l->p12->termTable->1->1->0->1->3->connectbutton2span",
1454 - "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->3",
1455 - "default.handlebars->13->596",
1456 - "default.handlebars->13->940",
1457 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea1->1->3",
1458 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->0->1->3",
1459 - "default-mobile.handlebars->9->233"
1347 + "default.handlebars->13->20",
1348 + "default-mobile.handlebars->9->11"
1349 ]
1350 },
1351 {
1463 - "en": "HW Connect",
1352 + "en": "Urdu",
1353 "xloc": [
1465 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->3->connectbutton1hspan",
1466 - "default.handlebars->container->column_l->p12->termTable->1->1->0->1->3->connectbutton2hspan",
1467 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea1->1->3"
1354 + "default.handlebars->13->852"
1355 ]
1356 },
1357 {
1471 - "en": "Disconnect",
1358 + "en": "This account does not have the rights to create a new device group.",
1359 "xloc": [
1473 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->3->disconnectbutton1span",
1474 - "default.handlebars->container->column_l->p12->termTable->1->1->0->1->3->disconnectbutton2span",
1475 - "default.handlebars->13->597",
1476 - "default.handlebars->13->941",
1477 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea1->1->3",
1478 - "default-mobile.handlebars->9->234"
1360 + "default.handlebars->13->887",
1361 + "default-mobile.handlebars->9->48"
1362 ]
1363 },
1364 {
1482 - "en": "Disconnected",
1365 + "en": "Installation Type",
1366 "xloc": [
1484 - "default.handlebars->container->column_l->p11->deskarea0->deskarea1->3->deskstatus",
1485 - "default.handlebars->container->column_l->p12->termTable->1->1->0->1->3->termstatus",
1486 - "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->3->p13Status",
1487 - "default.handlebars->13->8",
1488 - "default.handlebars->13->152",
1489 - "default.handlebars->13->168",
1490 - "default.handlebars->13->171",
1491 - "default.handlebars->13->175",
1492 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea1->1->3->deskstatus",
1493 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->0->1->3->p13Status",
1494 - "default-mobile.handlebars->9->1"
1367 + "default.handlebars->13->254",
1368 + "default.handlebars->13->276"
1369 ]
1370 },
1371 {
1498 - "en": "Refresh",
1372 + "en": "Display name",
1373 "xloc": [
1500 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsAreaTop->DeskToolsRefreshButton",
1501 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
1502 - "default.handlebars->container->column_l->p40->3->3",
1503 - "default.handlebars->13->362",
1504 - "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->3",
1505 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea3->deskarea3x->DeskTools->DeskToolsRefreshButton",
1506 - "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->3"
1374 + "default.handlebars->13->567"
1375 ]
1376 },
1377 {
1510 - "en": "Processes",
1378 + "en": "MeshCentral Server Peering",
1379 "xloc": [
1512 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsAreaTop->deskToolsTopTabProcess",
1513 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea3->deskarea3x->DeskTools->DeskToolsBar"
1380 + "default.handlebars->13->1253"
1381 ]
1382 },
1383 {
1517 - "en": "Services",
1384 + "en": "Offline Users",
1385 "xloc": [
1519 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsAreaTop->deskToolsTopTabService"
1386 + "default.handlebars->13->1115"
1387 ]
1388 },
1389 {
1523 - "en": "Sort by process id",
1390 + "en": "{{{installflags}}}",
1391 "xloc": [
1525 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsArea->DeskToolsProcessTab->deskToolsHeader"
1392 + "agentinvite.handlebars->3->7"
1393 ]
1394 },
1395 {
1529 - "en": "PID",
1396 + "en": "Marathi",
1397 "xloc": [
1531 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsArea->DeskToolsProcessTab->deskToolsHeader->1",
1532 - "default.handlebars->13->569",
1533 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea3->deskarea3x->DeskTools->5->1->0"
1398 + "default.handlebars->13->781"
1399 ]
1400 },
1401 {
1537 - "en": "Name",
1402 + "en": "add one",
1403 "xloc": [
1539 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsArea->DeskToolsProcessTab->deskToolsHeader->3",
1540 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsArea->DeskToolsServiceTab->deskToolsServiceHeader->3",
1541 - "default.handlebars->13->32",
1542 - "default.handlebars->13->41",
1543 - "default.handlebars->13->55",
1544 - "default.handlebars->13->566",
1545 - "default.handlebars->13->893",
1546 - "default.handlebars->13->920",
1547 - "default.handlebars->13->1003",
1548 - "default.handlebars->13->1111",
1549 - "default.handlebars->13->1154",
1550 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea3->deskarea3x->DeskTools->5->1->1",
1551 - "default-mobile.handlebars->9->53",
1552 - "default-mobile.handlebars->9->132",
1553 - "default-mobile.handlebars->9->274",
1554 - "default-mobile.handlebars->9->287"
1404 + "default.handlebars->13->159",
1405 + "default.handlebars->13->161"
1406 ]
1407 },
1408 {
1558 - "en": "Sort by state",
1409 + "en": "Fixed width interface",
1410 "xloc": [
1560 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsArea->DeskToolsServiceTab->deskToolsServiceHeader"
1411 + "agentinvite.handlebars->container->topbar->uiMenuButton->uiMenu",
1412 + "default.handlebars->container->topbar->1->1->uiMenuButton->uiMenu",
1413 + "error404.handlebars->container->topbar->uiMenuButton->uiMenu",
1414 + "login.handlebars->container->topbar->uiMenuButton->uiMenu",
1415 + "terms.handlebars->container->topbar->uiMenuButton->uiMenu"
1416 ]
1417 },
1418 {
1564 - "en": "State",
1419 + "en": "{0}k in 1 file. {1}k maximum",
1420 "xloc": [
1566 - "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsArea->DeskToolsServiceTab->deskToolsServiceHeader->1",
1567 - "default.handlebars->13->568"
1421 + "default.handlebars->13->1079"
1422 ]
1423 },
1424 {
1571 - "en": "Session time",
1425 + "en": "Intel&reg; AMT desktop and serial events.",
1426 "xloc": [
1573 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->1",
1574 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1"
1427 + "default.handlebars->13->867"
1428 ]
1429 },
1430 {
1578 - "en": "Tools",
1431 + "en": "Deep Sleep",
1432 "xloc": [
1580 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->1"
1433 + "default.handlebars->13->312",
1434 + "default-mobile.handlebars->9->107"
1435 ]
1436 },
1437 {
1584 - "en": "Toggle tools view",
1438 + "en": "English (Australia)",
1439 "xloc": [
1586 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->1"
1440 + "default.handlebars->13->713"
1441 ]
1442 },
1443 {
1590 - "en": "Open chat window to this computer",
1444 + "en": "This page does not exist",
1445 "xloc": [
1592 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->1"
1446 + "error404.handlebars->container->column_l->3"
1447 ]
1448 },
1449 {
1596 - "en": "Display a notification on the remote computer",
1450 + "en": "Encoding",
1451 "xloc": [
1598 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->1"
1452 + "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->3->3"
1453 ]
1454 },
1455 {
1602 - "en": "Open a web address on remote computer",
1456 + "en": "Intel&reg; AMT detected",
1457 "xloc": [
1604 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->1"
1458 + "default.handlebars->13->491",
1459 + "default.handlebars->13->492",
1460 + "default-mobile.handlebars->9->199"
1461 ]
1462 },
1463 {
1608 - "en": "Ctrl+Alt+Del",
1464 + "en": "Wake-up",
1465 "xloc": [
1610 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->1",
1611 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->1"
1466 + "default.handlebars->13->503",
1467 + "default-mobile.handlebars->9->203"
1468 ]
1469 },
1470 {
1615 - "en": "Win",
1471 + "en": "Upload will overwrite {0} file{1}. Continue?",
1472 "xloc": [
1617 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->3",
1618 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->5"
1473 + "default.handlebars->13->629",
1474 + "default.handlebars->13->1099"
1475 ]
1476 },
1477 {
1622 - "en": "Win+Down",
1478 + "en": "Scaling",
1479 "xloc": [
1624 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->5",
1625 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->7"
1480 + "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->1",
1481 + "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->3"
1482 ]
1483 },
1484 {
1629 - "en": "Win+Up",
1485 + "en": "Are you sure you want to delete node {0}?",
1486 + "fr": "Êtes-vous sûr de vouloir supprimer le noeud {0}?",
1487 "xloc": [
1631 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->7",
1632 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->9"
1488 + "default.handlebars->13->528"
1489 ]
1490 },
1491 {
1636 - "en": "Win+L",
1492 + "en": "MPS Server",
1493 "xloc": [
1638 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->9",
1639 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->11"
1494 + "default.handlebars->13->229",
1495 + "default.handlebars->13->234"
1496 ]
1497 },
1498 {
1643 - "en": "Win+M",
1499 + "en": "Clear the core",
1500 "xloc": [
1645 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->11",
1646 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->13"
1501 + "default.handlebars->13->645"
1502 ]
1503 },
1504 {
1650 - "en": "Shift+Win+M",
1505 + "en": "Copy valid codes to clipboard",
1506 "xloc": [
1652 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->13",
1653 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->15"
1507 + "default.handlebars->13->98"
1508 ]
1509 },
1510 {
1657 - "en": "Win+R",
1511 + "en": "Event Details",
1512 "xloc": [
1659 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->15",
1660 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->17"
1513 + "default.handlebars->13->633"
1514 ]
1515 },
1516 {
1664 - "en": "Alt-F4",
1517 + "en": "Power off devices",
1518 "xloc": [
1666 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->17",
1667 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->19"
1519 + "default.handlebars->13->345"
1520 ]
1521 },
1522 {
1671 - "en": "Ctrl-W",
1523 + "en": "Apple™ MacOS",
1524 "xloc": [
1673 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->19",
1674 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->21"
1525 + "agentinvite.handlebars->container->column_l->5->macostab->1"
1526 ]
1527 },
1528 {
1678 - "en": "Alt-Tab",
1529 + "en": "These settings can be used to connect MQTT for this device.",
1530 "xloc": [
1680 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->21",
1681 - "default-mobile.handlebars->dialog->3->dialog3->deskkeys->23"
1531 + "default.handlebars->13->134"
1532 ]
1533 },
1534 {
1685 - "en": "Win+Left",
1535 + "en": "Maltese",
1536 "xloc": [
1687 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->23"
1537 + "default.handlebars->13->779"
1538 ]
1539 },
1540 {
1691 - "en": "Win+Right",
1541 + "en": "NodeJS",
1542 "xloc": [
1693 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->25"
1543 + "default.handlebars->13->413",
1544 + "default-mobile.handlebars->9->163"
1545 ]
1546 },
1547 {
1697 - "en": "Send",
1548 + "en": "{0} non-alphanumeric",
1549 "xloc": [
1699 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3",
1700 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1",
1701 - "messenger.handlebars->xbottom"
1550 + "login.handlebars->5->17",
1551 + "login-mobile.handlebars->5->17"
1552 ]
1553 },
1554 {
1705 - "en": "Clipboard",
1555 + "en": "1 more user not shown, use search box to look for users...",
1556 "xloc": [
1707 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3"
1557 + "default.handlebars->13->1116"
1558 ]
1559 },
1560 {
1711 - "en": "Type",
1561 + "en": "Moldavian",
1562 "xloc": [
1713 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3",
1714 - "default.handlebars->13->575",
1715 - "default.handlebars->13->894",
1716 - "default.handlebars->13->923",
1717 - "default.handlebars->13->974",
1718 - "default.handlebars->13->977",
1719 - "default-mobile.handlebars->9->54",
1720 - "default-mobile.handlebars->9->277"
1563 + "default.handlebars->13->782"
1564 ]
1565 },
1566 {
1724 - "en": "Toggle mouse and keyboard input",
1567 + "en": "Cree",
1568 "xloc": [
1726 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->9"
1569 + "default.handlebars->13->706"
1570 ]
1571 },
1572 {
1730 - "en": "Input",
1573 + "en": "Windows (UnInstall)",
1574 "xloc": [
1732 - "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->9->DeskControlSpan",
1733 - "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea4->1->3->11->DeskControlSpan"
1575 + "default.handlebars->13->274"
1576 ]
1577 },
1578 {
1737 - "en": "Terminal -",
1579 + "en": "Group",
1580 "xloc": [
1739 - "default.handlebars->container->column_l->p12->p12title->3"
1581 + "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSort->sortselect->1",
1582 + "default.handlebars->13->381",
1583 + "default-mobile.handlebars->9->131"
1584 ]
1585 },
1586 {
1743 - "en": "CR+LF",
1587 + "en": "Agent Console",
1588 "xloc": [
1745 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSettingsButtons",
1746 - "default.handlebars->13->584",
1747 - "default.handlebars->13->593"
1589 + "default.handlebars->13->1045",
1590 + "default-mobile.handlebars->9->312"
1591 ]
1592 },
1593 {
1751 - "en": "Toggle what the return key will send",
1594 + "en": "Chinese (Hong Kong)",
1595 "xloc": [
1753 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSettingsButtons"
1596 + "default.handlebars->13->700"
1597 ]
1598 },
1599 {
1757 - "en": "Intel (F10 = ESC+[OM)",
1600 + "en": "Confim {0} of {1} entrie{2} to this location?",
1601 "xloc": [
1759 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSettingsButtons",
1760 - "default.handlebars->13->590"
1602 + "default.handlebars->13->1092",
1603 + "default-mobile.handlebars->9->83"
1604 ]
1605 },
1606 {
1764 - "en": "Toggle F1 to F10 keys emulation type",
1607 + "en": "Ctrl-W",
1608 "xloc": [
1766 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSettingsButtons"
1609 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->19",
1610 + "default-mobile.handlebars->dialog->3->dialog3->deskkeys->21"
1611 ]
1612 },
1613 {
1770 - "en": "Extended Ascii",
1614 + "en": "Allow users to manage this device group and devices in this group.",
1615 + "fr": "Autoriser les utilisateurs à gérer ce groupe et les périphériques de ce groupe.",
1616 "xloc": [
1772 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSettingsButtons"
1617 + "default.handlebars->13->1018"
1618 ]
1619 },
1620 {
1776 - "en": "Toggle terminal emulation type",
1621 + "en": "Free",
1622 "xloc": [
1778 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSettingsButtons"
1623 + "default.handlebars->13->1231",
1624 + "default.handlebars->13->1233"
1625 ]
1626 },
1627 {
1782 - "en": "80x25",
1628 + "en": "Manual Certificate",
1629 "xloc": [
1784 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSizeDropDown->termSizeList->0"
1630 + "default.handlebars->13->216"
1631 ]
1632 },
1633 {
1788 - "en": "100x30",
1634 + "en": "Rotate Right",
1635 "xloc": [
1790 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSizeDropDown->termSizeList->1"
1636 + "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1637 ]
1638 },
1639 {
1794 - "en": "Send the selected special key",
1640 + "en": "Aragonese",
1641 "xloc": [
1796 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1"
1642 + "default.handlebars->13->684"
1643 ]
1644 },
1645 {
1800 - "en": "Ctl-C",
1646 + "en": "No network interface information available for this device.",
1647 "xloc": [
1802 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->3"
1648 + "default.handlebars->13->47"
1649 ]
1650 },
1651 {
1806 - "en": "Ctl-X",
1652 + "en": "Show server error log",
1653 "xloc": [
1808 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->3"
1654 + "default.handlebars->container->column_l->p6->p2ServerActions->3->p2ServerActionsErrors->0"
1655 ]
1656 },
1657 {
1812 - "en": "ESC",
1658 + "en": "Soft-Off",
1659 "xloc": [
1814 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->3"
1660 + "default.handlebars->13->316",
1661 + "default-mobile.handlebars->9->109"
1662 ]
1663 },
1664 {
1818 - "en": "Backspace",
1665 + "en": "Download the list of users with one of the file formats below.",
1666 "xloc": [
1820 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->3"
1667 + "default.handlebars->13->1140"
1668 ]
1669 },
1670 {
1824 - "en": "Paste text into the terminal",
1671 + "en": "Unknown Version & State",
1672 + "fr": "Version et état inconnus",
1673 "xloc": [
1826 - "default.handlebars->container->column_l->p12->termTable->1->1->6->1->3"
1674 + "default.handlebars->13->427",
1675 + "default-mobile.handlebars->9->177"
1676 ]
1677 },
1678 {
1830 - "en": "Files -",
1679 + "en": "Center map here",
1680 + "fr": "Centré la carte ici",
1681 "xloc": [
1832 - "default.handlebars->container->column_l->p13->p13title->3"
1682 + "default.handlebars->13->364"
1683 ]
1684 },
1685 {
1836 - "en": "Edit",
1686 + "en": "Spanish (Argentina)",
1687 "xloc": [
1838 - "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3"
1688 + "default.handlebars->13->817"
1689 ]
1690 },
1691 {
1842 - "en": "Intel® AMT -",
1692 + "en": "Create a new group of devices.",
1693 "xloc": [
1844 - "default.handlebars->container->column_l->p14->p14title->5"
1694 + "default.handlebars->13->162"
1695 ]
1696 },
1697 {
1848 - "en": "Information about current core running on this agent",
1698 + "en": "Send",
1699 "xloc": [
1850 - "default.handlebars->container->column_l->p15->consoleTable->1->0->1->1"
1700 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3",
1701 + "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1",
1702 + "messenger.handlebars->xbottom"
1703 ]
1704 },
1705 {
1854 - "en": "Agent Action",
1706 + "en": "Intel&reg; AMT CIRA",
1707 "xloc": [
1856 - "default.handlebars->container->column_l->p15->consoleTable->1->0->1->1"
1708 + "default.handlebars->13->454",
1709 + "default-mobile.handlebars->9->188"
1710 ]
1711 },
1712 {
1860 - "en": "Change the agent Java Script code module",
1713 + "en": "80x25",
1714 "xloc": [
1862 - "default.handlebars->container->column_l->p15->consoleTable->1->0->1->1"
1715 + "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSizeDropDown->termSizeList->0"
1716 ]
1717 },
1718 {
1866 - "en": "Download console text",
1719 + "en": "FileSystemDriver",
1720 "xloc": [
1868 - "default.handlebars->container->column_l->p15->consoleTable->1->0->1->1"
1721 + "default.handlebars->13->570"
1722 ]
1723 },
1724 {
1872 - "en": "Agent",
1725 + "en": ", run it and press \"Install\" or \"Connect\".",
1726 "xloc": [
1874 - "default.handlebars->container->column_l->p15->consoleTable->1->6->1->1->1->0->p15outputselecttd->p15outputselect->1",
1875 - "default.handlebars->13->143",
1876 - "default.handlebars->13->327",
1877 - "default-mobile.handlebars->9->118",
1878 - "default-mobile.handlebars->9->171",
1879 - "default-mobile.handlebars->9->187"
1727 + "agentinvite.handlebars->container->column_l->5->wintab64->3",
1728 + "agentinvite.handlebars->container->column_l->5->wintab32->3"
1729 ]
1730 },
1731 {
1883 - "en": "MQTT",
1732 + "en": "RAW8, Slow",
1733 "xloc": [
1885 - "default.handlebars->container->column_l->p15->consoleTable->1->6->1->1->1->0->p15outputselecttd->p15outputselect->3",
1886 - "default.handlebars->13->151",
1887 - "default.handlebars->13->335",
1888 - "default.handlebars->13->460",
1889 - "default.handlebars->13->639",
1890 - "default.handlebars->13->640",
1891 - "default-mobile.handlebars->9->122",
1892 - "default-mobile.handlebars->9->191"
1734 + "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->3->d7desktopmode->5",
1735 + "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->3->d7desktopmode->5"
1736 ]
1737 },
1738 {
1896 - "en": "Clear",
1739 + "en": "User",
1740 "xloc": [
1898 - "default.handlebars->container->column_l->p15->consoleTable->1->6->1->1->1->0->7",
1899 - "default.handlebars->container->column_l->p41->3->1",
1900 - "default.handlebars->13->620",
1901 - "default.handlebars->13->622",
1902 - "default.handlebars->13->624",
1903 - "default.handlebars->13->626",
1904 - "default.handlebars->13->1097",
1905 - "default-mobile.handlebars->9->25",
1906 - "default-mobile.handlebars->9->88",
1907 - "default-mobile.handlebars->9->260",
1908 - "default-mobile.handlebars->9->262",
1909 - "default-mobile.handlebars->9->264",
1910 - "default-mobile.handlebars->9->266",
1911 - "messenger.handlebars->xbottom"
1741 + "default.handlebars->13->136",
1742 + "default.handlebars->13->153",
1743 + "default.handlebars->13->971",
1744 + "default.handlebars->13->1125",
1745 + "default-mobile.handlebars->9->324"
1746 ]
1747 },
1748 {
1915 - "en": "Events -",
1916 - "xloc": [
1917 - "default.handlebars->container->column_l->p16->p16title->3",
1918 - "default.handlebars->container->column_l->p31->3"
1749 + "en": "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.",
1750 + "xloc": [
1751 + "default.handlebars->13->81"
1752 ]
1753 },
1754 {
1922 - "en": "Details -",
1755 + "en": "Mesh Relay",
1756 "xloc": [
1924 - "default.handlebars->container->column_l->p17->p17title->3"
1757 + "default.handlebars->13->458"
1758 ]
1759 },
1760 {
1928 - "en": "My Server Stats",
1761 + "en": "Invite someone to install the mesh agent on this mesh.",
1762 "xloc": [
1930 - "default.handlebars->container->column_l->p40->1"
1763 + "default.handlebars->13->191",
1764 + "default.handlebars->13->964"
1765 ]
1766 },
1767 {
1934 - "en": "Connections",
1768 + "en": "Intel&reg; AMT is routable.",
1769 "xloc": [
1936 - "default.handlebars->container->column_l->p40->3->1->p40type->1"
1770 + "default.handlebars->13->146",
1771 + "default.handlebars->13->330"
1772 ]
1773 },
1774 {
1940 - "en": "Memory",
1775 + "en": "Send user notification",
1776 "xloc": [
1942 - "default.handlebars->container->column_l->p40->3->1->p40type->3",
1943 - "default.handlebars->13->36",
1944 - "default.handlebars->13->1237"
1777 + "default.handlebars->13->1212"
1778 ]
1779 },
1780 {
1948 - "en": "Last 3 hours",
1781 + "en": "Show devices operating system name",
1782 "xloc": [
1950 - "default.handlebars->container->column_l->p40->3->1->p40time->1"
1783 + "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar->7"
1784 ]
1785 },
1786 {
1954 - "en": "Last 8 hours",
1787 + "en": "Swedish (Finland)",
1788 "xloc": [
1956 - "default.handlebars->container->column_l->p40->3->1->p40time->3"
1789 + "default.handlebars->13->839"
1790 ]
1791 },
1792 {
1960 - "en": "Last day",
1793 + "en": "Remove this device",
1794 "xloc": [
1962 - "default.handlebars->container->column_l->p40->3->1->p40time->5"
1795 + "default.handlebars->13->471"
1796 ]
1797 },
1798 {
1966 - "en": "Last week",
1799 + "en": "CIRA",
1800 "xloc": [
1968 - "default.handlebars->container->column_l->p40->3->1->p40time->7"
1801 + "default.handlebars->13->145",
1802 + "default.handlebars->13->329",
1803 + "default.handlebars->13->988",
1804 + "default.handlebars->13->993",
1805 + "default-mobile.handlebars->9->119"
1806 ]
1807 },
1808 {
1972 - "en": "Last 30 days",
1809 + "en": "Edit remote desktop settings",
1810 "xloc": [
1974 - "default.handlebars->container->column_l->p40->3->1->p40time->9"
1811 + "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
1812 ]
1813 },
1814 {
1978 - "en": "Download data points (.csv)",
1815 + "en": "Manage security keys",
1816 "xloc": [
1980 - "default.handlebars->container->column_l->p40->3->1"
1817 + "default.handlebars->container->column_l->p2->p2AccountSecurity->3->manageHardwareOtp->1->0"
1818 ]
1819 },
1820 {
1984 - "en": "Log-X",
1821 + "en": "You will now need a valid token to login again.",
1822 "xloc": [
1986 - "default.handlebars->container->column_l->p40->3->3->3"
1823 + "default.handlebars->13->85"
1824 ]
1825 },
1826 {
1990 - "en": "My Server Tracing",
1827 + "en": "OK",
1828 "xloc": [
1992 - "default.handlebars->container->column_l->p41->1"
1829 + "default.handlebars->container->dialog->idx_dlgButtonBar",
1830 + "default.handlebars->13->448",
1831 + "default.handlebars->13->910",
1832 + "default-mobile.handlebars->dialog->idx_dlgButtonBar",
1833 + "default-mobile.handlebars->9->39",
1834 + "login.handlebars->dialog->idx_dlgButtonBar",
1835 + "login-mobile.handlebars->dialog->idx_dlgButtonBar",
1836 + "player.htm->p11->dialog->idx_dlgButtonBar"
1837 ]
1838 },
1839 {
1996 - "en": "Last 100",
1840 + "en": "Information",
1841 "xloc": [
1998 - "default.handlebars->container->column_l->p41->3->1->p41limitdropdown->1"
1842 + "default.handlebars->contextMenu->cxinfo->0"
1843 ]
1844 },
1845 {
2002 - "en": "Download trace (.csv)",
1846 + "en": "These files are shared publicly, click \"link\" to get public url.",
1847 + "fr": "Ces fichiers sont partagés publiquement, cliquez sur \"lien\" pour obtenir une URL publique.",
1848 "xloc": [
2004 - "default.handlebars->container->column_l->p41->3->1"
1849 + "default.handlebars->container->column_l->p5->p5filetable->p5PublicShare->0"
1850 ]
1851 },
1852 {
2008 - "en": "Tracing",
1853 + "en": "id, name, email, creation, lastlogin, groups, authfactors",
1854 "xloc": [
2010 - "default.handlebars->container->column_l->p41->3->3"
1855 + "default.handlebars->13->1146"
1856 ]
1857 },
1858 {
2014 - "en": "None",
1859 + "en": "Download data points (.csv)",
1860 "xloc": [
2016 - "default.handlebars->container->column_l->p41->3->3->p41traceStatus",
2017 - "default.handlebars->13->25",
2018 - "default.handlebars->13->127",
2019 - "default.handlebars->13->140",
2020 - "default.handlebars->13->141",
2021 - "default.handlebars->13->377",
2022 - "default.handlebars->13->385",
2023 - "default.handlebars->13->387",
2024 - "default.handlebars->13->462",
2025 - "default.handlebars->13->922",
2026 - "default.handlebars->13->926",
2027 - "default.handlebars->13->938",
2028 - "default.handlebars->13->943",
2029 - "default.handlebars->13->1073",
2030 - "default.handlebars->13->1198",
2031 - "default.handlebars->13->1202",
2032 - "default-mobile.handlebars->9->72",
2033 - "default-mobile.handlebars->9->90",
2034 - "default-mobile.handlebars->9->92",
2035 - "default-mobile.handlebars->9->130",
2036 - "default-mobile.handlebars->9->135",
2037 - "default-mobile.handlebars->9->137",
2038 - "default-mobile.handlebars->9->193",
2039 - "default-mobile.handlebars->9->242",
2040 - "default-mobile.handlebars->9->276"
1861 + "default.handlebars->container->column_l->p40->3->1"
1862 ]
1863 },
1864 {
2044 - "en": "Plugins -",
1865 + "en": "Other",
1866 "xloc": [
2046 - "default.handlebars->container->column_l->p19->1"
1867 + "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->5->3"
1868 ]
1869 },
1870 {
2050 - "en": "Verify Email",
1871 + "en": "Details -",
1872 "xloc": [
2052 - "default.handlebars->container->footer->3->verifyEmailId2"
1873 + "default.handlebars->container->column_l->p17->p17title->3"
1874 ]
1875 },
1876 {
2056 - "en": "Terms & Privacy",
1877 + "en": "Yiddish",
1878 "xloc": [
2058 - "default.handlebars->container->footer->3->3",
2059 - "download.handlebars->container->page_content->footer->1->1->0->3->1",
2060 - "login.handlebars->container->footer->3->1",
2061 - "login-mobile.handlebars->container->footer->1->1->0->3->1",
2062 - "message.handlebars->container->page_content->footer->1->1->0->3->1"
1879 + "default.handlebars->13->859"
1880 ]
1881 },
1882 {
2066 - "en": "File Selection",
1883 + "en": "64bit version of the MeshAgent",
1884 "xloc": [
2068 - "default.handlebars->container->dialog->dialogBody->dialog3->d3upload->1"
1885 + "default.handlebars->13->285",
1886 + "default.handlebars->13->299"
1887 ]
1888 },
1889 {
2072 - "en": "Local file upload",
1890 + "en": "English (South Africa)",
1891 "xloc": [
2074 - "default.handlebars->container->dialog->dialogBody->dialog3->d3upload->d3uploadMode->1"
1892 + "default.handlebars->13->720"
1893 ]
1894 },
1895 {
2078 - "en": "Server file selection",
1896 + "en": "No New Device Groups",
1897 "xloc": [
2080 - "default.handlebars->container->dialog->dialogBody->dialog3->d3upload->d3uploadMode->3"
1898 + "default.handlebars->13->1175"
1899 ]
1900 },
1901 {
2084 - "en": "Upload File",
1902 + "en": "Intel&reg; SM",
1903 "xloc": [
2086 - "default.handlebars->container->dialog->dialogBody->dialog3->d3localmode->1",
2087 - "default.handlebars->13->611",
2088 - "default.handlebars->13->628",
2089 - "default.handlebars->13->630",
2090 - "default.handlebars->13->1091",
2091 - "default.handlebars->13->1098",
2092 - "default-mobile.handlebars->9->82",
2093 - "default-mobile.handlebars->9->251",
2094 - "default-mobile.handlebars->9->269"
1904 + "default.handlebars->13->442",
1905 + "default-mobile.handlebars->9->185"
1906 ]
1907 },
1908 {
2098 - "en": "Agent Remote Desktop",
1909 + "en": "MyKey",
1910 "xloc": [
2100 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->1",
2101 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->1"
1911 + "default.handlebars->13->657",
1912 + "default.handlebars->13->660"
1913 ]
1914 },
1915 {
2105 - "en": "Quality",
1916 + "en": "Server Quota",
1917 "xloc": [
2107 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->3->1",
2108 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->3->3"
1918 + "default.handlebars->13->1191"
1919 ]
1920 },
1921 {
2112 - "en": "Scaling",
1922 + "en": "ARM-Linaro",
1923 "xloc": [
2114 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->1",
2115 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->3"
1924 + "default.handlebars->13->414",
1925 + "default-mobile.handlebars->9->164"
1926 ]
1927 },
1928 {
2119 - "en": "100%",
1929 + "en": "Remote computer is not powered on, click here to issue a power command.",
1930 "xloc": [
2121 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->d7bitmapscaling->1",
2122 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->d7bitmapscaling->1"
1931 + "default.handlebars->container->column_l->p11->p11warning2->3",
1932 + "default.handlebars->container->column_l->p12->p12warning2->3"
1933 ]
1934 },
1935 {
2126 - "en": "87.5%",
1936 + "en": "{0} bytes",
1937 + "fr": "{0} octets",
1938 "xloc": [
2128 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->d7bitmapscaling->3",
2129 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->d7bitmapscaling->3"
1939 + "default.handlebars->13->1084",
1940 + "default-mobile.handlebars->9->75"
1941 ]
1942 },
1943 {
2133 - "en": "75%",
1944 + "en": "MeshCentral Errors",
1945 "xloc": [
2135 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->d7bitmapscaling->5",
2136 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->d7bitmapscaling->5"
1946 + "default.handlebars->13->914"
1947 ]
1948 },
1949 {
2140 - "en": "62.5%",
1950 + "en": "(optional)",
1951 "xloc": [
2142 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->d7bitmapscaling->7",
2143 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->d7bitmapscaling->7"
1952 + "default.handlebars->13->259"
1953 ]
1954 },
1955 {
2147 - "en": "50%",
1956 + "en": "Add Local",
1957 "xloc": [
2149 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->d7bitmapscaling->9",
2150 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->d7bitmapscaling->9"
1958 + "default.handlebars->13->182"
1959 ]
1960 },
1961 {
2154 - "en": "37.5%",
1962 + "en": "Spanish (Bolivia)",
1963 "xloc": [
2156 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->d7bitmapscaling->11",
2157 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->d7bitmapscaling->11"
1964 + "default.handlebars->13->818"
1965 ]
1966 },
1967 {
2161 - "en": "25%",
1968 + "en": "tablinks",
1969 "xloc": [
2163 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->d7bitmapscaling->13",
2164 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->d7bitmapscaling->13"
1970 + "agentinvite.handlebars->3->18"
1971 ]
1972 },
1973 {
2168 - "en": "12.5%",
1974 + "en": "Hungarian",
1975 "xloc": [
2170 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->d7bitmapscaling->15",
2171 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->d7bitmapscaling->15"
1976 + "default.handlebars->13->755"
1977 ]
1978 },
1979 {
2175 - "en": "Frame rate",
1980 + "en": "MAC address",
1981 "xloc": [
2177 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->7->1"
1982 + "default.handlebars->13->59"
1983 ]
1984 },
1985 {
2181 - "en": "Fast",
1986 + "en": "Croatian",
1987 "xloc": [
2183 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->7->d7framelimiter->1",
2184 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->7->d7framelimiter->1"
1988 + "default.handlebars->13->707"
1989 ]
1990 },
1991 {
2188 - "en": "Slow",
1992 + "en": "Sanskrit",
1993 "xloc": [
2190 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->7->d7framelimiter->5",
2191 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->7->d7framelimiter->5"
1994 + "default.handlebars->13->807"
1995 ]
1996 },
1997 {
2195 - "en": "Very slow",
1998 + "en": "Frisian",
1999 "xloc": [
2197 - "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->7->d7framelimiter->7",
2198 - "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->7->d7framelimiter->7"
2000 + "default.handlebars->13->738"
2001 ]
2002 },
2003 {
2202 - "en": "Intel® AMT Hardware KVM",
2004 + "en": "Intel® AMT Redirection port or KVM feature is disabled",
2005 "xloc": [
2204 - "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->1",
2205 - "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->1"
2006 + "default.handlebars->container->column_l->p11->p11warning->3",
2007 + "default.handlebars->container->column_l->p12->p12warning->3"
2008 ]
2009 },
2010 {
2209 - "en": "Image Encoding",
2011 + "en": "Punjabi (Pakistan)",
2012 "xloc": [
2211 - "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->3->1"
2013 + "default.handlebars->13->798"
2014 ]
2015 },
2016 {
2215 - "en": "RLE8, Fastest",
2017 + "en": "Alt-Tab",
2018 "xloc": [
2217 - "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->3->d7desktopmode->1",
2218 - "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->3->d7desktopmode->1"
2019 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->21",
2020 + "default-mobile.handlebars->dialog->3->dialog3->deskkeys->23"
2021 ]
2022 },
2023 {
2222 - "en": "RLE16, Recommended",
2024 + "en": "Press the key button now.",
2025 "xloc": [
2224 - "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->3->d7desktopmode->3",
2225 - "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->3->d7desktopmode->3"
2026 + "default.handlebars->13->111"
2027 ]
2028 },
2029 {
2229 - "en": "RAW8, Slow",
2030 + "en": "No Intel&reg; AMT devices in this group",
2031 "xloc": [
2231 - "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->3->d7desktopmode->5",
2232 - "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->3->d7desktopmode->5"
2032 + "default-mobile.handlebars->9->93"
2033 ]
2034 },
2035 {
2236 - "en": "RAW16, Very Slow",
2036 + "en": "Kazakh",
2037 "xloc": [
2238 - "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->3->d7desktopmode->7",
2239 - "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->3->d7desktopmode->7"
2038 + "default.handlebars->13->765"
2039 ]
2040 },
2041 {
2243 - "en": "Other Settings",
2042 + "en": "Status",
2043 + "fr": "Statut",
2044 "xloc": [
2245 - "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->5->1"
2045 + "default.handlebars->13->1216"
2046 ]
2047 },
2048 {
2249 - "en": "Show Focus Tool",
2049 + "en": "User interface selection",
2050 "xloc": [
2251 - "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->5->d7otherset->1",
2252 - "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->5->1->1"
2051 + "agentinvite.handlebars->container->topbar",
2052 + "default.handlebars->container->topbar->1->1",
2053 + "error404.handlebars->container->topbar",
2054 + "login.handlebars->container->topbar",
2055 + "terms.handlebars->container->topbar"
2056 ]
2057 },
2058 {
2256 - "en": "Show Local Mouse Cursor",
2059 + "en": "Win+M",
2060 "xloc": [
2258 - "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->5->d7otherset->3",
2259 - "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->5->1->3"
2061 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->11",
2062 + "default-mobile.handlebars->dialog->3->dialog3->deskkeys->13"
2063 ]
2064 },
2065 {
2263 - "en": "Local Keyboard Map",
2066 + "en": "English (Zimbabwe)",
2067 "xloc": [
2265 - "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->5->d7otherset->5"
2068 + "default.handlebars->13->724"
2069 ]
2070 },
2071 {
2269 - "en": "Cancel",
2072 + "en": "No devices found.",
2073 "xloc": [
2271 - "default.handlebars->container->dialog->idx_dlgButtonBar",
2272 - "default.handlebars->13->909",
2273 - "default-mobile.handlebars->dialog->idx_dlgButtonBar",
2274 - "default-mobile.handlebars->9->38",
2275 - "login.handlebars->dialog->idx_dlgButtonBar",
2276 - "login-mobile.handlebars->dialog->idx_dlgButtonBar",
2277 - "player.htm->p11->dialog->idx_dlgButtonBar"
2074 + "default.handlebars->13->370"
2075 ]
2076 },
2077 {
2281 - "en": "OK",
2078 + "en": "Last agent address",
2079 "xloc": [
2283 - "default.handlebars->container->dialog->idx_dlgButtonBar",
2284 - "default.handlebars->13->448",
2285 - "default.handlebars->13->910",
2286 - "default-mobile.handlebars->dialog->idx_dlgButtonBar",
2287 - "default-mobile.handlebars->9->39",
2288 - "login.handlebars->dialog->idx_dlgButtonBar",
2289 - "login-mobile.handlebars->dialog->idx_dlgButtonBar",
2290 - "player.htm->p11->dialog->idx_dlgButtonBar"
2080 + "default.handlebars->13->49",
2081 + "default.handlebars->13->50",
2082 + "default.handlebars->13->52"
2083 ]
2084 },
2085 {
2294 - "en": "Powered",
2086 + "en": "Hebrew",
2087 "xloc": [
2296 - "default.handlebars->13->1",
2297 - "default.handlebars->13->306",
2298 - "default-mobile.handlebars->9->97",
2299 - "default-mobile.handlebars->9->104"
2088 + "default.handlebars->13->753"
2089 ]
2090 },
2091 {
2303 - "en": "Sleep",
2092 + "en": "Delete",
2093 "xloc": [
2305 - "default.handlebars->13->2",
2306 - "default.handlebars->13->3",
2307 - "default.handlebars->13->4",
2308 - "default.handlebars->13->504",
2309 - "default-mobile.handlebars->9->98",
2310 - "default-mobile.handlebars->9->99",
2311 - "default-mobile.handlebars->9->100",
2312 - "default-mobile.handlebars->9->204"
2094 + "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
2095 + "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
2096 + "default.handlebars->container->dialog->idx_dlgButtonBar->5",
2097 + "default.handlebars->13->607",
2098 + "default.handlebars->13->1087",
2099 + "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->1",
2100 + "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->1",
2101 + "default-mobile.handlebars->9->78",
2102 + "default-mobile.handlebars->9->247",
2103 + "player.htm->p11->dialog->idx_dlgButtonBar->5"
2104 ]
2105 },
2106 {
2316 - "en": "Hibernating",
2107 + "en": "Operation",
2108 "xloc": [
2318 - "default.handlebars->13->5",
2319 - "default.handlebars->13->314",
2320 - "default-mobile.handlebars->9->101",
2321 - "default-mobile.handlebars->9->108"
2109 + "default.handlebars->13->341",
2110 + "default.handlebars->13->508",
2111 + "default-mobile.handlebars->9->207"
2112 ]
2113 },
2114 {
2325 - "en": "Power off",
2115 + "en": "DNS suffix",
2116 "xloc": [
2327 - "default.handlebars->13->6",
2328 - "default.handlebars->13->506",
2329 - "default-mobile.handlebars->9->102",
2330 - "default-mobile.handlebars->9->206"
2117 + "default.handlebars->13->57"
2118 ]
2119 },
2120 {
2334 - "en": "Present",
2121 + "en": "Catalan",
2122 "xloc": [
2336 - "default.handlebars->13->7",
2337 - "default.handlebars->13->318",
2338 - "default-mobile.handlebars->9->103",
2339 - "default-mobile.handlebars->9->110"
2123 + "default.handlebars->13->696"
2124 ]
2125 },
2126 {
2343 - "en": "Connecting...",
2127 + "en": "Walloon",
2128 "xloc": [
2345 - "default.handlebars->13->9",
2346 - "default.handlebars->13->169",
2347 - "default.handlebars->13->172",
2348 - "default.handlebars->13->176",
2349 - "default.handlebars->13->631",
2350 - "default-mobile.handlebars->9->2",
2351 - "default-mobile.handlebars->9->6",
2352 - "default-mobile.handlebars->9->270"
2129 + "default.handlebars->13->856"
2130 ]
2131 },
2132 {
2356 - "en": "Setup...",
2133 + "en": "Username",
2134 + "fr": "Nom d'utilisateur",
2135 "xloc": [
2358 - "default.handlebars->13->10",
2359 - "default.handlebars->13->170",
2360 - "default.handlebars->13->173",
2361 - "default.handlebars->13->177",
2362 - "default-mobile.handlebars->9->3"
2136 + "default.handlebars->13->197",
2137 + "default.handlebars->13->227",
2138 + "default.handlebars->13->513",
2139 + "default-mobile.handlebars->9->209",
2140 + "player.htm->3->4"
2141 ]
2142 },
2143 {
2366 - "en": "Connected",
2144 + "en": "No Credentials",
2145 "xloc": [
2368 - "default.handlebars->13->11",
2369 - "default-mobile.handlebars->9->4"
2146 + "default.handlebars->13->435",
2147 + "default.handlebars->13->436",
2148 + "default-mobile.handlebars->9->181",
2149 + "default-mobile.handlebars->9->182"
2150 ]
2151 },
2152 {
2373 - "en": "Intel&reg; AMT Connected",
2153 + "en": "{{{domain}}}",
2154 "xloc": [
2375 - "default.handlebars->13->12",
2376 - "default-mobile.handlebars->9->5"
2155 + "agentinvite.handlebars->3->1"
2156 ]
2157 },
2158 {
2380 - "en": "Ctrl",
2159 + "en": "Minimum length of {0}",
2160 "xloc": [
2382 - "default.handlebars->13->13"
2161 + "login.handlebars->5->12",
2162 + "login-mobile.handlebars->5->12"
2163 ]
2164 },
2165 {
2386 - "en": "Unable to perform authentication",
2166 + "en": "Copyright 2013 jQuery Foundation and other contributors",
2167 "xloc": [
2388 - "default.handlebars->13->14",
2389 - "default-mobile.handlebars->9->7"
2168 + "terms.handlebars->container->column_l->47->1",
2169 + "terms-mobile.handlebars->container->page_content->column_l->47->1"
2170 ]
2171 },
2172 {
2393 - "en": "Unable to connect web socket",
2173 + "en": "Edit Device Notes",
2174 "xloc": [
2395 - "default.handlebars->13->15",
2396 - "default-mobile.handlebars->9->8"
2175 + "default.handlebars->13->1035",
2176 + "default-mobile.handlebars->9->303"
2177 ]
2178 },
2179 {
2400 - "en": "Please add two-factor backup codes. If the current factor is lost, there is not way to recover this account.",
2180 + "en": "Server Updates",
2181 "xloc": [
2402 - "default.handlebars->13->16"
2182 + "default.handlebars->13->1172"
2183 ]
2184 },
2185 {
2406 - "en": "Two factor authentication",
2186 + "en": "Reset account",
2187 "xloc": [
2408 - "default.handlebars->13->17"
2188 + "login.handlebars->container->column_l->centralTable->1->0->logincell->loginpanel->1->resetAccountDiv->3",
2189 + "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->loginpanel->1->resetAccountDiv->3"
2190 ]
2191 },
2192 {
2412 - "en": " - Reset on next login.",
2193 + "en": "User browser value",
2194 "xloc": [
2414 - "default.handlebars->13->18",
2415 - "default.handlebars->13->19",
2416 - "default-mobile.handlebars->9->9",
2417 - "default-mobile.handlebars->9->10"
2195 + "default.handlebars->13->861"
2196 ]
2197 },
2198 {
2421 - "en": " - Reset in {0} minute{1}.",
2199 + "en": "You can reactivate this feature at any time.",
2200 "xloc": [
2423 - "default.handlebars->13->20",
2424 - "default-mobile.handlebars->9->11"
2201 + "default.handlebars->13->90"
2202 ]
2203 },
2204 {
2428 - "en": " - Reset in {0} hour{1}.",
2205 + "en": "Pass Hint:",
2206 "xloc": [
2430 - "default.handlebars->13->21",
2431 - "default-mobile.handlebars->9->12"
2207 + "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->createpanel->1->1->9->1->createPanelHint->1"
2208 ]
2209 },
2210 {
2435 - "en": " - Reset in {0} day{1}.",
2211 + "en": "Irish",
2212 "xloc": [
2437 - "default.handlebars->13->22",
2438 - "default-mobile.handlebars->9->13"
2213 + "default.handlebars->13->759"
2214 ]
2215 },
2216 {
2442 - "en": "{0} second{1} until disconnect",
2217 + "en": "Drag & drop a .mcrec file or click \\\"Open File...\\\"",
2218 "xloc": [
2444 - "default.handlebars->13->23"
2219 + "player.htm->3->18"
2220 ]
2221 },
2222 {
2448 - "en": "{0} minute{1} until disconnect",
2223 + "en": "Username:",
2224 + "fr": "Nom d'utilisateur:",
2225 "xloc": [
2450 - "default.handlebars->13->24"
2226 + "login.handlebars->container->column_l->centralTable->1->0->logincell->loginpanel->1->7->1->0->loginusername",
2227 + "login.handlebars->container->column_l->centralTable->1->0->logincell->createpanel->1->9->1->nuUserRow->nuUser",
2228 + "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->loginpanel->1->7->1->0->loginusername",
2229 + "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->createpanel->1->1->9->1->nuUserRow->1"
2230 ]
2231 },
2232 {
2454 - "en": "No information for this device.",
2233 + "en": "My Devices",
2234 "xloc": [
2456 - "default.handlebars->13->26"
2235 + "default.handlebars->container->page_leftbar",
2236 + "default.handlebars->container->topbar->1->1->MainMenuSpan->1->0->MainMenuMyDevices",
2237 + "default.handlebars->container->column_l->p1->2->0"
2238 ]
2239 },
2240 {
2460 - "en": "BIOS",
2241 + "en": "Swedish (Sweden)",
2242 "xloc": [
2462 - "default.handlebars->13->27"
2243 + "default.handlebars->13->840"
2244 ]
2245 },
2246 {
2466 - "en": "Vendor",
2247 + "en": "Alternate (F10 = ESC+0)",
2248 "xloc": [
2468 - "default.handlebars->13->28",
2469 - "default.handlebars->13->31"
2249 + "default.handlebars->13->591"
2250 ]
2251 },
2252 {
2473 - "en": "Version",
2253 + "en": "Open a web address on remote computer",
2254 "xloc": [
2475 - "default.handlebars->13->29",
2476 - "default.handlebars->13->34",
2477 - "default.handlebars->13->42"
2255 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->1"
2256 ]
2257 },
2258 {
2481 - "en": "Motherboard",
2259 + "en": "Ctl-X",
2260 "xloc": [
2483 - "default.handlebars->13->30"
2261 + "default.handlebars->container->column_l->p12->termTable->1->1->6->1->3"
2262 ]
2263 },
2264 {
2487 - "en": "Serial",
2265 + "en": "Disconnected",
2266 "xloc": [
2489 - "default.handlebars->13->33"
2267 + "default.handlebars->container->column_l->p11->deskarea0->deskarea1->3->deskstatus",
2268 + "default.handlebars->container->column_l->p12->termTable->1->1->0->1->3->termstatus",
2269 + "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->3->p13Status",
2270 + "default.handlebars->13->8",
2271 + "default.handlebars->13->152",
2272 + "default.handlebars->13->168",
2273 + "default.handlebars->13->171",
2274 + "default.handlebars->13->175",
2275 + "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea1->1->3->deskstatus",
2276 + "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->0->1->3->p13Status",
2277 + "default-mobile.handlebars->9->1"
2278 ]
2279 },
2280 {
2493 - "en": "Identifier",
2281 + "en": "Old password:",
2282 "xloc": [
2495 - "default.handlebars->13->35"
2283 + "default.handlebars->13->880",
2284 + "default-mobile.handlebars->9->41"
2285 ]
2286 },
2287 {
2499 - "en": "Capacity / Speed",
2288 + "en": "Only files less than 200k can be edited.",
2289 "xloc": [
2501 - "default.handlebars->13->37"
2290 + "default.handlebars->13->613",
2291 + "default-mobile.handlebars->9->253"
2292 ]
2293 },
2294 {
2505 - "en": "{0} Mb, {1} Mhz",
2295 + "en": "Select an operation to perform on all selected devices. Actions will be performed only with proper rights.",
2296 "xloc": [
2507 - "default.handlebars->13->38"
2297 + "default.handlebars->13->340"
2298 ]
2299 },
2300 {
2511 - "en": "Part Number",
2301 + "en": "Windows 64bit service",
2302 "xloc": [
2513 - "default.handlebars->13->39"
2303 + "default.handlebars->13->394",
2304 + "default-mobile.handlebars->9->144"
2305 ]
2306 },
2516 - {
2517 - "en": "Operating System",
2518 - "xloc": [
2519 - "default.handlebars->13->40",
2520 - "default.handlebars->13->241",
2521 - "default.handlebars->13->270",
2522 - "default.handlebars->13->445"
2307 + {
2308 + "en": "Ctl-C",
2309 + "xloc": [
2310 + "default.handlebars->container->column_l->p12->termTable->1->1->6->1->3"
2311 ]
2312 },
2313 {
2526 - "en": "Architecture",
2314 + "en": "Spanish (Mexico)",
2315 "xloc": [
2528 - "default.handlebars->13->43"
2316 + "default.handlebars->13->827"
2317 ]
2318 },
2319 {
2532 - "en": "Last seen:",
2320 + "en": "Don\\'t connect to server",
2321 "xloc": [
2534 - "default.handlebars->13->44",
2535 - "default.handlebars->13->495"
2322 + "default.handlebars->13->990"
2323 ]
2324 },
2325 {
2539 - "en": "Success",
2326 + "en": "Intel® AMT -",
2327 "xloc": [
2541 - "default.handlebars->13->45"
2328 + "default.handlebars->container->column_l->p14->p14title->5"
2329 ]
2330 },
2331 {
2545 - "en": "Failed",
2332 + "en": "Last Access",
2333 "xloc": [
2547 - "default.handlebars->13->46"
2334 + "default.handlebars->13->1112"
2335 ]
2336 },
2337 {
2551 - "en": "No network interface information available for this device.",
2338 + "en": "{{{terms}}}",
2339 "xloc": [
2553 - "default.handlebars->13->47"
2340 + "terms.handlebars->3->1"
2341 ]
2342 },
2343 {
2557 - "en": "Last agent connection",
2344 + "en": " and authenticate to the server using this username and any password.",
2345 + "fr": "et vous authentifier sur le serveur en utilisant ce nom d'utilisateur et n'importe quel mot de passe.",
2346 "xloc": [
2559 - "default.handlebars->13->48"
2347 + "default.handlebars->13->223"
2348 ]
2349 },
2350 {
2563 - "en": "Last agent address",
2351 + "en": "Vietnamese",
2352 "xloc": [
2565 - "default.handlebars->13->49",
2566 - "default.handlebars->13->50",
2567 - "default.handlebars->13->52"
2353 + "default.handlebars->13->854"
2354 ]
2355 },
2356 {
2571 - "en": "Copy address to clipboard",
2357 + "en": "{0} second{1}",
2358 "xloc": [
2573 - "default.handlebars->13->51",
2574 - "default.handlebars->13->53",
2575 - "default.handlebars->13->62",
2576 - "default.handlebars->13->64",
2577 - "default.handlebars->13->66"
2359 + "player.htm->3->3"
2360 ]
2361 },
2362 {
2581 - "en": "Last interfaces update",
2363 + "en": "Topic",
2364 "xloc": [
2583 - "default.handlebars->13->54"
2365 + "default.handlebars->13->519"
2366 ]
2367 },
2368 {
2587 - "en": "Description",
2369 + "en": "Action",
2370 "xloc": [
2589 - "default.handlebars->13->56",
2590 - "default.handlebars->13->388",
2591 - "default.handlebars->13->389",
2592 - "default.handlebars->13->547",
2593 - "default.handlebars->13->897",
2594 - "default.handlebars->13->921",
2595 - "default.handlebars->13->1004",
2596 - "default-mobile.handlebars->9->57",
2597 - "default-mobile.handlebars->9->138",
2598 - "default-mobile.handlebars->9->139",
2599 - "default-mobile.handlebars->9->221",
2600 - "default-mobile.handlebars->9->275",
2601 - "default-mobile.handlebars->9->288"
2371 + "default.handlebars->13->643"
2372 ]
2373 },
2374 {
2605 - "en": "DNS suffix",
2375 + "en": "Win+Left",
2376 "xloc": [
2607 - "default.handlebars->13->57"
2377 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->3->deskkeys->23"
2378 ]
2379 },
2380 {
2611 - "en": "Copy name to clipboard",
2381 + "en": "Edit User Device Group Permissions",
2382 "xloc": [
2613 - "default.handlebars->13->58"
2383 + "default.handlebars->13->1039"
2384 ]
2385 },
2386 {
2617 - "en": "MAC address",
2387 + "en": "Descend by name",
2388 "xloc": [
2619 - "default.handlebars->13->59"
2389 + "default.handlebars->container->column_l->p5->p5toolbar->1->2->p5filesubhead->1->p5sortdropdown->7",
2390 + "default.handlebars->container->column_l->p13->p13toolbar->1->4->1->1->p13sortdropdown->7",
2391 + "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->2->1->1->1->0->3->p5sortdropdown->7",
2392 + "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->4->1->1->1->0->3->p13sortdropdown->7"
2393 ]
2394 },
2395 {
2623 - "en": "Copy MAC address to clipboard",
2396 + "en": "Details",
2397 "xloc": [
2625 - "default.handlebars->13->60",
2626 - "default.handlebars->13->68"
2398 + "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevInfo"
2399 ]
2400 },
2401 {
2630 - "en": "IPv4 address",
2402 + "en": "Pause",
2403 "xloc": [
2632 - "default.handlebars->13->61"
2404 + "player.htm->p11->deskarea0->deskarea4->3"
2405 ]
2406 },
2407 {
2636 - "en": "IPv4 mask",
2408 + "en": "Click ok to send a verification mail to:",
2409 "xloc": [
2638 - "default.handlebars->13->63"
2410 + "default.handlebars->13->869",
2411 + "default-mobile.handlebars->9->31"
2412 ]
2413 },
2414 {
2642 - "en": "IPv4 gateway",
2415 + "en": "Scan Network",
2416 "xloc": [
2644 - "default.handlebars->13->65"
2417 + "default.handlebars->13->184"
2418 ]
2419 },
2420 {
2648 - "en": "Gateway MAC",
2421 + "en": "Broadcast Message",
2422 + "fr": "Diffusion d'un Message",
2423 "xloc": [
2650 - "default.handlebars->13->67"
2424 + "default.handlebars->13->1153"
2425 ]
2426 },
2427 {
2654 - "en": "Unknown",
2428 + "en": "No devices in this mesh",
2429 "xloc": [
2656 - "default.handlebars->13->69",
2657 - "default.handlebars->13->70",
2658 - "default.handlebars->13->336",
2659 - "default.handlebars->13->390",
2660 - "default.handlebars->13->418",
2661 - "default.handlebars->13->419",
2662 - "default-mobile.handlebars->9->123",
2663 - "default-mobile.handlebars->9->140",
2664 - "default-mobile.handlebars->9->168",
2665 - "default-mobile.handlebars->9->169"
2430 + "default.handlebars->13->160"
2431 ]
2432 },
2433 {
2669 - "en": "Current Version",
2434 + "en": "Device Action",
2435 "xloc": [
2671 - "default.handlebars->13->71"
2436 + "default.handlebars->13->509",
2437 + "default-mobile.handlebars->9->208"
2438 ]
2439 },
2440 {
2675 - "en": "Latest Version",
2441 + "en": "User Names",
2442 "xloc": [
2677 - "default.handlebars->13->72"
2443 + "default.handlebars->13->1020"
2444 ]
2445 },
2446 {
2681 - "en": "MeshCentral Version",
2447 + "en": "wget https://",
2448 "xloc": [
2683 - "default.handlebars->13->73",
2684 - "default.handlebars->13->74",
2685 - "default.handlebars->13->912"
2449 + "agentinvite.handlebars->3->32",
2450 + "agentinvite.handlebars->3->36"
2451 ]
2452 },
2453 {
2689 - "en": "Check and click OK to start server self-update.",
2454 + "en": "Copyright (C) 2011 Joel Martin This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.",
2455 "xloc": [
2691 - "default.handlebars->13->75"
2456 + "terms.handlebars->container->column_l->63->1",
2457 + "terms-mobile.handlebars->container->page_content->column_l->63->1"
2458 ]
2459 },
2460 {
2695 - "en": "MeshCentral Server Errors",
2461 + "en": "{{{serverhttps}}}",
2462 "xloc": [
2697 - "default.handlebars->13->76",
2698 - "default.handlebars->13->78"
2463 + "agentinvite.handlebars->3->5"
2464 ]
2465 },
2466 {
2702 - "en": "Server has no error log.",
2467 + "en": "Server Rights",
2468 "xloc": [
2704 - "default.handlebars->13->77"
2469 + "default.handlebars->13->1190"
2470 ]
2471 },
2472 {
2708 - "en": "Download error log",
2473 + "en": "MeshCentral Router is a Windows tool for TCP port mapping. You can, for example, RDP into a remote device thru this server.",
2474 "xloc": [
2710 - "default.handlebars->13->79"
2475 + "default.handlebars->13->534"
2476 ]
2477 },
2478 {
2714 - "en": "Check and click OK to clear error log.",
2479 + "en": "French (Canada)",
2480 "xloc": [
2716 - "default.handlebars->13->80"
2481 + "default.handlebars->13->733"
2482 ]
2483 },
2484 {
2720 - "en": "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.",
2485 + "en": "Remote Desktop Settings",
2486 "xloc": [
2722 - "default.handlebars->13->81"
2487 + "default.handlebars->13->178",
2488 + "default.handlebars->13->555",
2489 + "default-mobile.handlebars->9->226"
2490 ]
2491 },
2492 {
2726 - "en": "Enter the token here for 2-step login:",
2493 + "en": "Requirements: {0}.",
2494 "xloc": [
2728 - "default.handlebars->13->82"
2495 + "default.handlebars->13->1162",
2496 + "default.handlebars->13->1221",
2497 + "default-mobile.handlebars->9->45"
2498 ]
2499 },
2500 {
2732 - "en": "Authenticator App",
2501 + "en": "Powered",
2502 "xloc": [
2734 - "default.handlebars->13->83",
2735 - "default.handlebars->13->88",
2736 - "default.handlebars->13->651",
2737 - "default.handlebars->13->653",
2738 - "default-mobile.handlebars->9->15",
2739 - "default-mobile.handlebars->9->18",
2740 - "default-mobile.handlebars->9->27",
2741 - "default-mobile.handlebars->9->29"
2503 + "default.handlebars->13->1",
2504 + "default.handlebars->13->306",
2505 + "default-mobile.handlebars->9->97",
2506 + "default-mobile.handlebars->9->104"
2507 ]
2508 },
2509 {
2745 - "en": "Authenticator app activation successful.",
2510 + "en": "Web Socket Relay",
2511 + "fr": "Relais Web Socket",
2512 "xloc": [
2747 - "default.handlebars->13->84"
2513 + "default.handlebars->13->1257"
2514 ]
2515 },
2516 {
2751 - "en": "You will now need a valid token to login again.",
2517 + "en": "Quality",
2518 "xloc": [
2753 - "default.handlebars->13->85"
2519 + "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->3->1",
2520 + "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->3->3"
2521 ]
2522 },
2523 {
2757 - "en": "2-step login activation failed.",
2524 + "en": "Cancel",
2525 + "fr": "Annuler",
2526 "xloc": [
2759 - "default.handlebars->13->86"
2527 + "default.handlebars->container->dialog->idx_dlgButtonBar",
2528 + "default.handlebars->13->909",
2529 + "default-mobile.handlebars->dialog->idx_dlgButtonBar",
2530 + "default-mobile.handlebars->9->38",
2531 + "login.handlebars->dialog->idx_dlgButtonBar",
2532 + "login-mobile.handlebars->dialog->idx_dlgButtonBar",
2533 + "player.htm->p11->dialog->idx_dlgButtonBar"
2534 ]
2535 },
2536 {
2763 - "en": "Clear the secret from the application and try again. You only have a few minutes to enter the proper code.",
2537 + "en": ", right click on it or press \"control\" and click on the file. Then select \"Open\" and follow the instructions.",
2538 "xloc": [
2765 - "default.handlebars->13->87"
2539 + "agentinvite.handlebars->container->column_l->5->macostab->3"
2540 ]
2541 },
2542 {
2769 - "en": "Authenticator application removed.",
2543 + "en": "Last changed: {0}",
2544 "xloc": [
2771 - "default.handlebars->13->89"
2545 + "default.handlebars->13->1197"
2546 ]
2547 },
2548 {
2775 - "en": "You can reactivate this feature at any time.",
2549 + "en": "Slovenian",
2550 "xloc": [
2777 - "default.handlebars->13->90"
2551 + "default.handlebars->13->813"
2552 ]
2553 },
2554 {
2781 - "en": "2-step login activation removal failed.",
2555 + "en": "Cookie encoder",
2556 "xloc": [
2783 - "default.handlebars->13->91"
2557 + "default.handlebars->13->1250"
2558 ]
2559 },
2560 {
2787 - "en": "Try again.",
2561 + "en": "Email Address Change",
2562 "xloc": [
2789 - "default.handlebars->13->92"
2563 + "default.handlebars->13->873",
2564 + "default-mobile.handlebars->9->35"
2565 ]
2566 },
2567 {
2793 - "en": "One time tokens can be used as secondary authentication. Generate a set, print them and keep them in a safe place.",
2568 + "en": "Edit Device Group",
2569 "xloc": [
2795 - "default.handlebars->13->93",
2796 - "default-mobile.handlebars->9->21"
2570 + "default.handlebars->13->1005",
2571 + "default.handlebars->13->1023",
2572 + "default.handlebars->13->1041",
2573 + "default-mobile.handlebars->9->289",
2574 + "default-mobile.handlebars->9->291",
2575 + "default-mobile.handlebars->9->308"
2576 ]
2577 },
2578 {
2800 - "en": "No Active Tokens",
2579 + "en": "Armenian",
2580 "xloc": [
2802 - "default.handlebars->13->94",
2803 - "default-mobile.handlebars->9->22"
2581 + "default.handlebars->13->685"
2582 ]
2583 },
2584 {
2807 - "en": "Close",
2585 + "en": "No Intel&reg; AMT devices in this mesh",
2586 "xloc": [
2809 - "default.handlebars->13->95",
2810 - "default.handlebars->13->103",
2811 - "default.handlebars->13->576",
2812 - "default-mobile.handlebars->9->23"
2587 + "default.handlebars->13->158"
2588 ]
2589 },
2590 {
2816 - "en": "Generate New Tokens",
2591 + "en": "Copy MAC address to clipboard",
2592 "xloc": [
2818 - "default.handlebars->13->96"
2593 + "default.handlebars->13->60",
2594 + "default.handlebars->13->68"
2595 ]
2596 },
2597 {
2822 - "en": "Clear Tokens",
2598 + "en": "Show connection toolbar",
2599 "xloc": [
2824 - "default.handlebars->13->97"
2600 + "default.handlebars->13->1009"
2601 ]
2602 },
2603 {
2828 - "en": "Copy valid codes to clipboard",
2604 + "en": "fullscreen",
2605 "xloc": [
2830 - "default.handlebars->13->98"
2606 + "agentinvite.handlebars->3->10",
2607 + "agentinvite.handlebars->3->12",
2608 + "terms.handlebars->3->3",
2609 + "terms.handlebars->3->5"
2610 ]
2611 },
2612 {
2834 - "en": "Manage Backup Codes",
2613 + "en": "No devices",
2614 "xloc": [
2836 - "default.handlebars->13->99",
2837 - "default-mobile.handlebars->9->26"
2615 + "default-mobile.handlebars->9->95"
2616 ]
2617 },
2618 {
2841 - "en": "<a href=\\\"https://www.yubico.com/\\\" rel=\\\"noreferrer noopener\\\" target=\\\"_blank\\\">Hardware keys</a> are used as secondary login authentication.",
2619 + "en": "Link Expiration",
2620 "xloc": [
2843 - "default.handlebars->13->100"
2621 + "default.handlebars->13->247",
2622 + "default.handlebars->13->261"
2623 ]
2624 },
2625 {
2847 - "en": "Remove",
2626 + "en": "Call Error",
2627 + "fr": "Erreur d'appel",
2628 "xloc": [
2849 - "default.handlebars->13->101"
2629 + "default.handlebars->13->1266"
2630 ]
2631 },
2632 {
2853 - "en": "No Keys Configured",
2633 + "en": "Log-X",
2634 "xloc": [
2855 - "default.handlebars->13->102"
2635 + "default.handlebars->container->column_l->p40->3->3->3"
2636 ]
2637 },
2638 {
2859 - "en": "Add Key",
2639 + "en": "Navajo",
2640 "xloc": [
2861 - "default.handlebars->13->104"
2641 + "default.handlebars->13->783"
2642 ]
2643 },
2644 {
2865 - "en": "Add YubiKey&reg; OTP",
2645 + "en": "Enter",
2646 "xloc": [
2867 - "default.handlebars->13->105"
2647 + "default.handlebars->13->899",
2648 + "default.handlebars->13->900"
2649 ]
2650 },
2651 {
2871 - "en": "Manage Security Keys",
2652 + "en": "Gujurati",
2653 "xloc": [
2873 - "default.handlebars->13->106"
2654 + "default.handlebars->13->751"
2655 ]
2656 },
2657 {
2877 - "en": "Add Security Key",
2658 + "en": "Last 1000",
2659 "xloc": [
2879 - "default.handlebars->13->107",
2880 - "default.handlebars->13->109",
2881 - "default.handlebars->13->112",
2882 - "default.handlebars->13->113",
2883 - "default.handlebars->13->662",
2884 - "default.handlebars->13->663"
2660 + "default.handlebars->container->column_l->p3->3->1->0->3->p3limitdropdown->9",
2661 + "default.handlebars->container->column_l->p16->3->1->0->5->p16limitdropdown->9",
2662 + "default.handlebars->container->column_l->p31->5->1->0->5->p31limitdropdown->9",
2663 + "default.handlebars->container->column_l->p41->3->1->p41limitdropdown->7"
2664 ]
2665 },
2666 {
2888 - "en": "Error, Unable to add key.",
2667 + "en": "Notification sound.",
2668 "xloc": [
2890 - "default.handlebars->13->108"
2669 + "default.handlebars->13->864"
2670 ]
2671 },
2672 {
2894 - "en": "ERROR: Unable to add key.",
2673 + "en": "Extended Ascii",
2674 "xloc": [
2896 - "default.handlebars->13->110"
2675 + "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSettingsButtons"
2676 ]
2677 },
2678 {
2900 - "en": "Press the key button now.",
2679 + "en": "Large",
2680 "xloc": [
2902 - "default.handlebars->13->111"
2681 + "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSize->sizeselect->5"
2682 ]
2683 },
2684 {
2906 - "en": "ERROR: ",
2685 + "en": "Polish",
2686 "xloc": [
2908 - "default.handlebars->13->114"
2687 + "default.handlebars->13->793"
2688 ]
2689 },
2690 {
2912 - "en": "Agent connected",
2691 + "en": "New Account...",
2692 "xloc": [
2914 - "default.handlebars->13->115",
2915 - "default.handlebars->13->487",
2916 - "default.handlebars->13->488"
2693 + "default.handlebars->container->column_l->p4->3->1->0->3->3"
2694 ]
2695 },
2696 {
2920 - "en": "Intel AMT detected",
2697 + "en": "Backup Codes",
2698 "xloc": [
2922 - "default.handlebars->13->116"
2699 + "default.handlebars->13->1206"
2700 ]
2701 },
2702 {
2926 - "en": "Intel AMT CIRA connected",
2703 + "en": "Network Interfaces",
2704 "xloc": [
2928 - "default.handlebars->13->117"
2705 + "default.handlebars->13->532"
2706 ]
2707 },
2708 {
2932 - "en": "MQTT connected",
2709 + "en": "Manage using a software agent",
2710 "xloc": [
2934 - "default.handlebars->13->118",
2935 - "default.handlebars->13->493"
2711 + "default.handlebars->13->895"
2712 ]
2713 },
2714 {
2939 - "en": "Agent disconnected",
2715 + "en": "1 week",
2716 + "fr": "1 semaine",
2717 "xloc": [
2941 - "default.handlebars->13->119"
2718 + "default.handlebars->13->130",
2719 + "default.handlebars->13->251",
2720 + "default.handlebars->13->265"
2721 ]
2722 },
2723 {
2945 - "en": "Intel AMT not detected",
2724 + "en": "RAW16, Very Slow",
2725 "xloc": [
2947 - "default.handlebars->13->120"
2726 + "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->3->d7desktopmode->7",
2727 + "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->3->d7desktopmode->7"
2728 ]
2729 },
2730 {
2951 - "en": "Intel AMT CIRA disconnected",
2731 + "en": "{0} Mb",
2732 "xloc": [
2953 - "default.handlebars->13->121"
2733 + "default.handlebars->13->1076"
2734 ]
2735 },
2736 {
2957 - "en": "MQTT disconnected",
2737 + "en": "Linux x86 (64bit)",
2738 "xloc": [
2959 - "default.handlebars->13->122"
2739 + "default.handlebars->13->539"
2740 ]
2741 },
2742 {
2963 - "en": "Unable to scan this address range.",
2743 + "en": "French (Monaco)",
2744 "xloc": [
2965 - "default.handlebars->13->123"
2745 + "default.handlebars->13->736"
2746 ]
2747 },
2748 {
2969 - "en": "Sample IP range values<br />192.168.0.100<br />192.168.1.0/24<br />192.167.0.1-192.168.0.100",
2749 + "en": "State",
2750 "xloc": [
2971 - "default.handlebars->13->124"
2751 + "default.handlebars->container->column_l->p11->deskarea0->deskarea3x->DeskTools->deskToolsArea->DeskToolsServiceTab->deskToolsServiceHeader->1",
2752 + "default.handlebars->13->568"
2753 ]
2754 },
2755 {
2975 - "en": " with TLS.",
2756 + "en": "Deactivate Client Control Mode (CCM)",
2757 "xloc": [
2977 - "default.handlebars->13->125"
2758 + "default.handlebars->13->979"
2759 ]
2760 },
2761 {
2981 - "en": " without TLS.",
2762 + "en": "{0} Kb",
2763 "xloc": [
2983 - "default.handlebars->13->126"
2764 + "default.handlebars->13->1075"
2765 ]
2766 },
2767 {
2987 - "en": "{0} hour{1}",
2768 + "en": "Hostname",
2769 "xloc": [
2989 - "default.handlebars->13->128"
2770 + "default.handlebars->13->195",
2771 + "default.handlebars->13->383",
2772 + "default.handlebars->13->384",
2773 + "default.handlebars->13->386",
2774 + "default.handlebars->13->546",
2775 + "default-mobile.handlebars->9->133",
2776 + "default-mobile.handlebars->9->134",
2777 + "default-mobile.handlebars->9->136",
2778 + "default-mobile.handlebars->9->220"
2779 ]
2780 },
2781 {
2993 - "en": "1 day",
2782 + "en": "Email is verified",
2783 "xloc": [
2995 - "default.handlebars->13->129",
2996 - "default.handlebars->13->250",
2997 - "default.handlebars->13->264"
2784 + "default.handlebars->13->1185"
2785 ]
2786 },
2787 {
3001 - "en": "1 week",
2788 + "en": "Full Screen. Hold shift to browser full screen.",
2789 "xloc": [
3003 - "default.handlebars->13->130",
3004 - "default.handlebars->13->251",
3005 - "default.handlebars->13->265"
2790 + "default.handlebars->container->column_l->p11->p11title->p11deviceNameHeader->devListToolbarViewIcons",
2791 + "default.handlebars->container->column_l->p14->p14title->devListToolbarViewIcons"
2792 ]
2793 },
2794 {
3009 - "en": "1 month",
2795 + "en": "Location Results",
2796 "xloc": [
3011 - "default.handlebars->13->131",
3012 - "default.handlebars->13->252",
3013 - "default.handlebars->13->266"
2797 + "default.handlebars->container->column_l->p1->xdevicesmap->xmapSearchResultsDlg->xmapSearchResultsBck->3"
2798 ]
2799 },
2800 {
3017 - "en": "Unlimited",
2801 + "en": "Scan for Intel&reg; AMT devices",
2802 "xloc": [
3019 - "default.handlebars->13->132",
3020 - "default.handlebars->13->253",
3021 - "default.handlebars->13->267"
2803 + "default.handlebars->13->212"
2804 ]
2805 },
2806 {
3025 - "en": "Invitation Link ({0})",
2807 + "en": "Indonesian",
2808 "xloc": [
3027 - "default.handlebars->13->133"
2809 + "default.handlebars->13->757"
2810 ]
2811 },
2812 {
3031 - "en": "These settings can be used to connect MQTT for this device.",
2813 + "en": "Chinese (Taiwan)",
2814 "xloc": [
3033 - "default.handlebars->13->134"
2815 + "default.handlebars->13->703"
2816 ]
2817 },
2818 {
3037 - "en": "MQTT Credentials",
2819 + "en": "Password",
2820 "xloc": [
3039 - "default.handlebars->13->135"
2821 + "default.handlebars->13->199",
2822 + "default.handlebars->13->228",
2823 + "default.handlebars->13->514",
2824 + "default.handlebars->13->1156",
2825 + "default.handlebars->13->1157",
2826 + "default.handlebars->13->1194",
2827 + "default.handlebars->13->1196",
2828 + "default.handlebars->13->1218",
2829 + "default.handlebars->13->1219",
2830 + "default-mobile.handlebars->9->210"
2831 ]
2832 },
2833 {
3043 - "en": "User",
2834 + "en": "Stats",
2835 "xloc": [
3045 - "default.handlebars->13->136",
3046 - "default.handlebars->13->153",
3047 - "default.handlebars->13->971",
3048 - "default.handlebars->13->1125",
3049 - "default-mobile.handlebars->9->324"
2836 + "default.handlebars->container->topbar->1->1->ServerSubMenuSpan->ServerSubMenu->1->0->ServerStats"
2837 ]
2838 },
2839 {
3053 - "en": "Address",
2840 + "en": "Check server version",
2841 "xloc": [
3055 - "default.handlebars->13->137",
3056 - "default.handlebars->13->154"
2842 + "default.handlebars->container->column_l->p6->p2ServerActions->3->p2ServerActionsVersion->0"
2843 ]
2844 },
2845 {
3060 - "en": "Connectivity",
2846 + "en": "7.Webtoolkit Javascript Base 64 – Creative Commons Attribution 2.0 UK License",
2847 "xloc": [
3062 - "default.handlebars->13->138",
3063 - "default.handlebars->13->155",
3064 - "default.handlebars->13->461",
3065 - "default-mobile.handlebars->9->192"
2848 + "terms.handlebars->container->column_l->73->1->0",
2849 + "terms-mobile.handlebars->container->page_content->column_l->73->1->0"
2850 ]
2851 },
2852 {
3069 - "en": ", Intel&reg; AMT only",
2853 + "en": "Large Focus",
2854 "xloc": [
3071 - "default.handlebars->13->139",
3072 - "default-mobile.handlebars->9->89"
2855 + "default.handlebars->13->561"
2856 ]
2857 },
2858 {
3076 - "en": "Mesh agent is connected and ready for use.",
2859 + "en": "Delete Node",
2860 "xloc": [
3078 - "default.handlebars->13->142",
3079 - "default.handlebars->13->326",
3080 - "default.handlebars->13->451"
2861 + "default.handlebars->13->530",
2862 + "default-mobile.handlebars->9->215"
2863 ]
2864 },
2865 {
3084 - "en": "Intel&reg; AMT CIRA is connected and ready for use.",
2866 + "en": "Zoom to fit extent",
2867 "xloc": [
3086 - "default.handlebars->13->144",
3087 - "default.handlebars->13->328",
3088 - "default.handlebars->13->453"
2868 + "default.handlebars->13->363"
2869 ]
2870 },
2871 {
3092 - "en": "CIRA",
2872 + "en": "Norwegian (Bokmal)",
2873 "xloc": [
3094 - "default.handlebars->13->145",
3095 - "default.handlebars->13->329",
3096 - "default.handlebars->13->988",
3097 - "default.handlebars->13->993",
3098 - "default-mobile.handlebars->9->119"
2874 + "default.handlebars->13->787"
2875 ]
2876 },
2877 {
3102 - "en": "Intel&reg; AMT is routable.",
2878 + "en": "View notes about this device group",
2879 "xloc": [
3104 - "default.handlebars->13->146",
3105 - "default.handlebars->13->330"
2880 + "default.handlebars->13->952"
2881 ]
2882 },
2883 {
3109 - "en": "AMT",
2884 + "en": "Used",
2885 "xloc": [
3111 - "default.handlebars->13->147",
3112 - "default.handlebars->13->331"
2886 + "default.handlebars->13->1230",
2887 + "default.handlebars->13->1232"
2888 ]
2889 },
2890 {
3116 - "en": "Mesh agent is reachable using another agent as relay.",
2891 + "en": "Arabic (Algeria)",
2892 "xloc": [
3118 - "default.handlebars->13->148",
3119 - "default.handlebars->13->332",
3120 - "default.handlebars->13->457"
2893 + "default.handlebars->13->668"
2894 ]
2895 },
2896 {
3124 - "en": "Relay",
2897 + "en": "To add a new Intel&reg; AMT device to device group \\\"{0}\\\" 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.",
2898 "xloc": [
3126 - "default.handlebars->13->149",
3127 - "default.handlebars->13->333",
3128 - "default-mobile.handlebars->9->121"
2899 + "default.handlebars->13->218"
2900 ]
2901 },
2902 {
3132 - "en": "MQTT connection to the device is active.",
2903 + "en": "Policy",
2904 "xloc": [
3134 - "default.handlebars->13->150",
3135 - "default.handlebars->13->334",
3136 - "default.handlebars->13->459"
2905 + "default.handlebars->13->904",
2906 + "default-mobile.handlebars->9->59"
2907 ]
2908 },
2909 {
3140 - "en": "No devices are included in any groups, click on a device\\'s \\\"Groups\\\" to add to a group.",
2910 + "en": "Arabic (Iraq)",
2911 "xloc": [
3142 - "default.handlebars->13->156"
2912 + "default.handlebars->13->671"
2913 ]
2914 },
2915 {
3146 - "en": "No devices matching this search.",
2916 + "en": "Sorbian",
2917 "xloc": [
3148 - "default.handlebars->13->157"
2918 + "default.handlebars->13->815"
2919 ]
2920 },
2921 {
3152 - "en": "No Intel&reg; AMT devices in this mesh",
2922 + "en": "Desktop Prompt",
2923 "xloc": [
3154 - "default.handlebars->13->158"
2924 + "default.handlebars->13->930"
2925 ]
2926 },
2927 {
3158 - "en": "add one",
2928 + "en": "French (Belgium)",
2929 "xloc": [
3160 - "default.handlebars->13->159",
3161 - "default.handlebars->13->161"
2930 + "default.handlebars->13->732"
2931 ]
2932 },
2933 {
3165 - "en": "No devices in this mesh",
2934 + "en": "No Rights",
2935 "xloc": [
3167 - "default.handlebars->13->160"
2936 + "default.handlebars->13->907",
2937 + "default.handlebars->13->969",
2938 + "default.handlebars->13->1056",
2939 + "default-mobile.handlebars->9->62",
2940 + "default-mobile.handlebars->9->282",
2941 + "default-mobile.handlebars->9->323"
2942 ]
2943 },
2944 {
3171 - "en": "Create a new group of devices.",
2945 + "en": "To add a new computer to device group \\\"{0}\\\", download the mesh agent and install it the computer to manage. This agent installer has server and device group information embedded within it.",
2946 "xloc": [
3173 - "default.handlebars->13->162"
2947 + "default.handlebars->13->291"
2948 ]
2949 },
2950 {
3177 - "en": "Add Device Group",
2951 + "en": "Norwegian (Nynorsk)",
2952 "xloc": [
3179 - "default.handlebars->13->163"
2953 + "default.handlebars->13->788"
2954 ]
2955 },
2956 {
3183 - "en": "Download MeshCmd, a command line tool that performs many functions.",
2957 + "en": "Czech",
2958 "xloc": [
3185 - "default.handlebars->13->164"
2959 + "default.handlebars->13->708"
2960 ]
2961 },
2962 {
3189 - "en": "MeshCmd",
2963 + "en": "Xhosa",
2964 "xloc": [
3191 - "default.handlebars->13->165"
2965 + "default.handlebars->13->858"
2966 ]
2967 },
2968 {
3195 - "en": "Download MeshCentral Router, a TCP port mapping tool.",
2969 + "en": "Estonian",
2970 "xloc": [
3197 - "default.handlebars->13->166"
2971 + "default.handlebars->13->726"
2972 ]
2973 },
2974 {
3201 - "en": "Router",
2975 + "en": "My Server Tracing",
2976 "xloc": [
3203 - "default.handlebars->13->167",
3204 - "default.handlebars->13->478"
2977 + "default.handlebars->container->column_l->p41->1"
2978 ]
2979 },
2980 {
3208 - "en": "{0} users",
2981 + "en": "Disabled",
2982 "xloc": [
3210 - "default.handlebars->13->174"
2983 + "default.handlebars->13->446"
2984 ]
2985 },
2986 {
3214 - "en": "Remote Desktop Settings",
2987 + "en": "meshagents?script=1 -O ./meshinstall.sh || wget http://",
2988 "xloc": [
3216 - "default.handlebars->13->178",
3217 - "default.handlebars->13->555",
3218 - "default-mobile.handlebars->9->226"
2989 + "agentinvite.handlebars->3->40",
2990 + "agentinvite.handlebars->3->45"
2991 ]
2992 },
2993 {
3222 - "en": "Add a new Intel&reg; AMT computer that is located on the internet.",
2994 + "en": "Confirm removal of authenticator application 2-step login?",
2995 "xloc": [
3224 - "default.handlebars->13->179",
3225 - "default.handlebars->13->954"
2996 + "default.handlebars->13->654",
2997 + "default-mobile.handlebars->9->30"
2998 ]
2999 },
3000 {
3229 - "en": "Add CIRA",
3001 + "en": "Search Location",
3002 "xloc": [
3231 - "default.handlebars->13->180"
3003 + "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devMapToolbar"
3004 ]
3005 },
3006 {
3235 - "en": "Add a new Intel&reg; AMT computer that is located on the local network.",
3007 + "en": "{0}m left",
3008 "xloc": [
3237 - "default.handlebars->13->181",
3238 - "default.handlebars->13->956"
3009 + "default-mobile.handlebars->9->69"
3010 ]
3011 },
3012 {
3242 - "en": "Add Local",
3013 + "en": "No Files",
3014 "xloc": [
3244 - "default.handlebars->13->182"
3015 + "default.handlebars->13->1051",
3016 + "default-mobile.handlebars->9->318"
3017 ]
3018 },
3019 {
3248 - "en": "Add a new Intel&reg; AMT computer by scanning the local network.",
3020 + "en": "none",
3021 "xloc": [
3250 - "default.handlebars->13->183"
3022 + "agentinvite.handlebars->3->17"
3023 ]
3024 },
3025 {
3254 - "en": "Scan Network",
3026 + "en": "Perform Intel AMT client control mode (CCM) activation to group \\\"{0}\\\" by downloading the MeshCMD tool and running it like this:",
3027 "xloc": [
3256 - "default.handlebars->13->184"
3028 + "default.handlebars->13->204"
3029 ]
3030 },
3031 {
3260 - "en": "Perform Intel AMT client control mode (CCM) activation.",
3032 + "en": "IPv4 address",
3033 "xloc": [
3262 - "default.handlebars->13->185",
3263 - "default.handlebars->13->958"
3034 + "default.handlebars->13->61"
3035 ]
3036 },
3037 {
3267 - "en": "Activation",
3038 + "en": "Arabic (Syria)",
3039 "xloc": [
3269 - "default.handlebars->13->186",
3270 - "default.handlebars->13->188",
3271 - "default.handlebars->13->959",
3272 - "default.handlebars->13->961"
3040 + "default.handlebars->13->680"
3041 ]
3042 },
3043 {
3276 - "en": "Perform Intel AMT admin control mode (ACM) activation.",
3044 + "en": "MIPS",
3045 "xloc": [
3278 - "default.handlebars->13->187",
3279 - "default.handlebars->13->960"
3046 + "default.handlebars->13->397",
3047 + "default-mobile.handlebars->9->147"
3048 ]
3049 },
3050 {
3283 - "en": "Add a new computer to this mesh by installing the mesh agent.",
3051 + "en": "Left bar interface",
3052 "xloc": [
3285 - "default.handlebars->13->189",
3286 - "default.handlebars->13->962"
3053 + "agentinvite.handlebars->container->topbar->uiMenuButton->uiMenu",
3054 + "default.handlebars->container->topbar->1->1->uiMenuButton->uiMenu",
3055 + "error404.handlebars->container->topbar->uiMenuButton->uiMenu",
3056 + "login.handlebars->container->topbar->uiMenuButton->uiMenu",
3057 + "terms.handlebars->container->topbar->uiMenuButton->uiMenu"
3058 ]
3059 },
3060 {
3290 - "en": "Add Agent",
3061 + "en": "Linux Poky x86-64bit",
3062 "xloc": [
3292 - "default.handlebars->13->190"
3063 + "default.handlebars->13->408",
3064 + "default-mobile.handlebars->9->158"
3065 ]
3066 },
3067 {
3296 - "en": "Invite someone to install the mesh agent on this mesh.",
3068 + "en": "Holding 1 entrie for move",
3069 "xloc": [
3298 - "default.handlebars->13->191",
3299 - "default.handlebars->13->964"
3070 + "default.handlebars->13->625",
3071 + "default-mobile.handlebars->9->265"
3072 ]
3073 },
3074 {
3303 - "en": "Invite",
3075 + "en": "Background & interactive",
3076 "xloc": [
3305 - "default.handlebars->13->192",
3306 - "default.handlebars->13->269",
3307 - "default.handlebars->13->965"
3077 + "default.handlebars->13->277"
3078 ]
3079 },
3080 {
3311 - "en": "Add a new Intel&reg; AMT device to device group \\\"{0}\\\".",
3081 + "en": "PowerShell Connect",
3082 "xloc": [
3313 - "default.handlebars->13->193"
3083 + "default.handlebars->termShellContextMenu->cxtermps"
3084 ]
3085 },
3086 {
3317 - "en": "Device Name",
3087 + "en": "Terminal -",
3088 + "fr": "Terminal -",
3089 "xloc": [
3319 - "default.handlebars->13->194",
3320 - "default.handlebars->13->545",
3321 - "default-mobile.handlebars->9->219"
3090 + "default.handlebars->container->column_l->p12->p12title->3"
3091 ]
3092 },
3093 {
3325 - "en": "Hostname",
3094 + "en": "Clear",
3095 "xloc": [
3327 - "default.handlebars->13->195",
3328 - "default.handlebars->13->383",
3329 - "default.handlebars->13->384",
3330 - "default.handlebars->13->386",
3331 - "default.handlebars->13->546",
3332 - "default-mobile.handlebars->9->133",
3333 - "default-mobile.handlebars->9->134",
3334 - "default-mobile.handlebars->9->136",
3335 - "default-mobile.handlebars->9->220"
3096 + "default.handlebars->container->column_l->p15->consoleTable->1->6->1->1->1->0->7",
3097 + "default.handlebars->container->column_l->p41->3->1",
3098 + "default.handlebars->13->620",
3099 + "default.handlebars->13->622",
3100 + "default.handlebars->13->624",
3101 + "default.handlebars->13->626",
3102 + "default.handlebars->13->1097",
3103 + "default-mobile.handlebars->9->25",
3104 + "default-mobile.handlebars->9->88",
3105 + "default-mobile.handlebars->9->260",
3106 + "default-mobile.handlebars->9->262",
3107 + "default-mobile.handlebars->9->264",
3108 + "default-mobile.handlebars->9->266",
3109 + "messenger.handlebars->xbottom"
3110 ]
3111 },
3112 {
3339 - "en": "Same as device name",
3113 + "en": "Quechua",
3114 "xloc": [
3341 - "default.handlebars->13->196"
3115 + "default.handlebars->13->799"
3116 ]
3117 },
3118 {
3345 - "en": "Username",
3119 + "en": "Intel® AMT Hardware KVM",
3120 "xloc": [
3347 - "default.handlebars->13->197",
3348 - "default.handlebars->13->227",
3349 - "default.handlebars->13->513",
3350 - "default-mobile.handlebars->9->209",
3351 - "player.htm->3->4"
3121 + "default.handlebars->container->dialog->dialogBody->dialog7->d7amtkvm->1",
3122 + "default-mobile.handlebars->dialog->3->dialog7->d7amtkvm->1"
3123 ]
3124 },
3125 {
3355 - "en": "admin",
3126 + "en": "Dutch (Belgian)",
3127 "xloc": [
3357 - "default.handlebars->13->198"
3128 + "default.handlebars->13->711"
3129 ]
3130 },
3131 {
3361 - "en": "Password",
3132 + "en": "Linux x86 (32bit)",
3133 "xloc": [
3363 - "default.handlebars->13->199",
3364 - "default.handlebars->13->228",
3365 - "default.handlebars->13->514",
3366 - "default.handlebars->13->1156",
3367 - "default.handlebars->13->1157",
3368 - "default.handlebars->13->1194",
3369 - "default.handlebars->13->1196",
3370 - "default.handlebars->13->1218",
3371 - "default.handlebars->13->1219",
3372 - "default-mobile.handlebars->9->210"
3134 + "default.handlebars->13->538"
3135 ]
3136 },
3137 {
3376 - "en": "Security",
3138 + "en": "Bosnian",
3139 "xloc": [
3378 - "default.handlebars->13->200",
3379 - "default.handlebars->13->515",
3380 - "default.handlebars->13->1207",
3381 - "default-mobile.handlebars->9->211"
3140 + "default.handlebars->13->693"
3141 ]
3142 },
3143 {
3385 - "en": "No TLS security",
3144 + "en": "Arabic (Libya)",
3145 "xloc": [
3387 - "default.handlebars->13->201",
3388 - "default.handlebars->13->516",
3389 - "default-mobile.handlebars->9->212"
3146 + "default.handlebars->13->675"
3147 ]
3148 },
3149 {
3393 - "en": "TLS security required",
3150 + "en": "Authenticator App",
3151 "xloc": [
3395 - "default.handlebars->13->202",
3396 - "default.handlebars->13->517",
3397 - "default-mobile.handlebars->9->213"
3152 + "default.handlebars->13->83",
3153 + "default.handlebars->13->88",
3154 + "default.handlebars->13->651",
3155 + "default.handlebars->13->653",
3156 + "default-mobile.handlebars->9->15",
3157 + "default-mobile.handlebars->9->18",
3158 + "default-mobile.handlebars->9->27",
3159 + "default-mobile.handlebars->9->29"
3160 ]
3161 },
3162 {
3401 - "en": "Add Intel&reg; AMT device",
3163 + "en": "Change email address",
3164 "xloc": [
3403 - "default.handlebars->13->203"
3165 + "default.handlebars->container->column_l->p2->p2AccountActions->3->accountChangeEmailAddressSpan->0",
3166 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->7->3->changeEmailId->0"
3167 ]
3168 },
3169 {
3407 - "en": "Perform Intel AMT client control mode (CCM) activation to group \\\"{0}\\\" by downloading the MeshCMD tool and running it like this:",
3170 + "en": "Rate",
3171 "xloc": [
3409 - "default.handlebars->13->204"
3172 + "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->7->3"
3173 ]
3174 },
3175 {
3413 - "en": "Intel&reg; AMT activation",
3176 + "en": "Actions",
3177 "xloc": [
3415 - "default.handlebars->13->205",
3416 - "default.handlebars->13->208"
3178 + "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1",
3179 + "default.handlebars->container->column_l->p12->termTable->1->1->0->1->1",
3180 + "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->1",
3181 + "default.handlebars->13->463",
3182 + "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea4->1->3",
3183 + "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->0->1->1"
3184 ]
3185 },
3186 {
3420 - "en": "Perform Intel AMT admin control mode (ACM) activation to group \\\"{0}\\\" by downloading the MeshCMD tool and running it like this:",
3187 + "en": "Current Version",
3188 "xloc": [
3422 - "default.handlebars->13->206"
3189 + "default.handlebars->13->71"
3190 ]
3191 },
3192 {
3426 - "en": "Intel AMT will need to be set with a Trusted FQDN in MEBx or have a wired LAN on the network:",
3193 + "en": "CIRA Server Commands",
3194 "xloc": [
3428 - "default.handlebars->13->207"
3195 + "default.handlebars->13->1261"
3196 ]
3197 },
3198 {
3432 - "en": "Enter a range of IP addresses to scan for Intel AMT devices.",
3199 + "en": "<b style=color:green>2-step login activation removed</b>. You can reactivate this feature at any time.",
3200 "xloc": [
3434 - "default.handlebars->13->209"
3201 + "default-mobile.handlebars->9->19"
3202 ]
3203 },
3204 {
3438 - "en": "IP Range",
3205 + "en": "1.AJAX Control Toolkit - New BSD License",
3206 "xloc": [
3440 - "default.handlebars->13->210"
3207 + "terms.handlebars->container->column_l->9->1->0",
3208 + "terms-mobile.handlebars->container->page_content->column_l->9->1->0"
3209 ]
3210 },
3211 {
3444 - "en": "Scan",
3212 + "en": "Display a notification on the remote computer",
3213 "xloc": [
3446 - "default.handlebars->13->211"
3214 + "default.handlebars->container->column_l->p11->deskarea0->deskarea4->1"
3215 ]
3216 },
3217 {
3450 - "en": "Scan for Intel&reg; AMT devices",
3218 + "en": "copy",
3219 "xloc": [
3452 - "default.handlebars->13->212"
3220 + "default.handlebars->13->1095",
3221 + "default-mobile.handlebars->9->86"
3222 ]
3223 },
3224 {
3456 - "en": "Scanning...",
3225 + "en": "Activated",
3226 + "fr": "Activé",
3227 "xloc": [
3458 - "default.handlebars->13->213"
3228 + "default.handlebars->13->424",
3229 + "default.handlebars->13->426",
3230 + "default-mobile.handlebars->9->174",
3231 + "default-mobile.handlebars->9->176"
3232 ]
3233 },
3234 {
3462 - "en": "MeshCommander Script",
3235 + "en": "click to reconnect",
3236 "xloc": [
3464 - "default.handlebars->13->214"
3237 + "default.handlebars->container->column_l->p0->p0message->2->0",
3238 + "default-mobile.handlebars->container->page_content->column_l->p0->1->p0message->2->0"
3239 ]
3240 },
3241 {
3468 - "en": "Manual Username/Password",
3242 + "en": "Desktop -",
3243 "xloc": [
3470 - "default.handlebars->13->215"
3244 + "default.handlebars->container->column_l->p11->p11title->p11deviceNameHeader->5"
3245 ]
3246 },
3247 {
3474 - "en": "Manual Certificate",
3248 + "en": "File Editor",
3249 "xloc": [
3476 - "default.handlebars->13->216"
3250 + "default.handlebars->13->612",
3251 + "default-mobile.handlebars->9->252"
3252 ]
3253 },
3254 {
3480 - "en": "Setup Method",
3255 + "en": "Server Restore",
3256 "xloc": [
3482 - "default.handlebars->13->217"
3257 + "default.handlebars->13->1171"
3258 ]
3259 },
3260 {
3486 - "en": "To add a new Intel&reg; AMT device to device group \\\"{0}\\\" 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.",
3261 + "en": "Add Security Key",
3262 + "fr": "Ajouter une clé de sécurité",
3263 "xloc": [
3488 - "default.handlebars->13->218"
3264 + "default.handlebars->13->107",
3265 + "default.handlebars->13->109",
3266 + "default.handlebars->13->112",
3267 + "default.handlebars->13->113",
3268 + "default.handlebars->13->662",
3269 + "default.handlebars->13->663"
3270 ]
3271 },
3272 {
3492 - "en": "Setup CIRA",
3273 + "en": "Enter text and click OK to remotely type it using a US english keyboard. Make sure to place the remote cursor at the correct position before proceeding.",
3274 "xloc": [
3494 - "default.handlebars->13->219"
3275 + "default.handlebars->13->562"
3276 ]
3277 },
3278 {
3498 - "en": "Cleanup CIRA",
3279 + "en": "Operating System",
3280 "xloc": [
3500 - "default.handlebars->13->220"
3281 + "default.handlebars->13->40",
3282 + "default.handlebars->13->241",
3283 + "default.handlebars->13->270",
3284 + "default.handlebars->13->445"
3285 ]
3286 },
3287 {
3504 - "en": "To add a new Intel&reg; AMT device to device group \\\"{0}\\\" with CIRA, load the following certificate as trusted root within Intel AMT",
3288 + "en": "Malayalam",
3289 "xloc": [
3506 - "default.handlebars->13->221"
3290 + "default.handlebars->13->778"
3291 ]
3292 },
3293 {
3510 - "en": " and authenticate to the server using this username and password.",
3294 + "en": "Last 3 hours",
3295 "xloc": [
3512 - "default.handlebars->13->222"
3296 + "default.handlebars->container->column_l->p40->3->1->p40time->1"
3297 ]
3298 },
3299 {
3516 - "en": " and authenticate to the server using this username and any password.",
3300 + "en": "Desktop",
3301 "xloc": [
3518 - "default.handlebars->13->223"
3302 + "default.handlebars->contextMenu->cxdesktop",
3303 + "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevDesktop",
3304 + "default.handlebars->13->357",
3305 + "default.handlebars->13->1006"
3306 ]
3307 },
3308 {
3522 - "en": "Root Certificate",
3309 + "en": "Medium",
3310 "xloc": [
3524 - "default.handlebars->13->224",
3525 - "default.handlebars->13->231"
3311 + "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSize->sizeselect->3",
3312 + "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->7->d7framelimiter->3",
3313 + "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->7->d7framelimiter->3"
3314 ]
3315 },
3316 {
3529 - "en": "MeshServerRootCert.cer",
3317 + "en": "Connecting...",
3318 "xloc": [
3531 - "default.handlebars->13->225"
3319 + "default.handlebars->13->9",
3320 + "default.handlebars->13->169",
3321 + "default.handlebars->13->172",
3322 + "default.handlebars->13->176",
3323 + "default.handlebars->13->631",
3324 + "default-mobile.handlebars->9->2",
3325 + "default-mobile.handlebars->9->6",
3326 + "default-mobile.handlebars->9->270"
3327 ]
3328 },
3329 {
3535 - "en": "Root Certificate File",
3330 + "en": "Download the list of events with one of the file formats below.",
3331 "xloc": [
3537 - "default.handlebars->13->226",
3538 - "default.handlebars->13->232"
3332 + "default.handlebars->13->1102"
3333 ]
3334 },
3335 {
3542 - "en": "MPS Server",
3336 + "en": " nodes",
3337 + "fr": "noeuds",
3338 "xloc": [
3544 - "default.handlebars->13->229",
3545 - "default.handlebars->13->234"
3339 + "default.handlebars->13->304",
3340 + "default-mobile.handlebars->9->125"
3341 ]
3342 },
3343 {
3549 - "en": "To add a new Intel&reg; AMT device to device group \\\"{0}\\\" 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.",
3344 + "en": "1/4 Speed",
3345 + "fr": "1/4 vitesse",
3346 "xloc": [
3551 - "default.handlebars->13->230"
3347 + "player.htm->p11->deskarea0->deskarea4->3->PlaySpeed->1"
3348 ]
3349 },
3350 {
3555 - "en": "Organization",
3351 + "en": "Rotate Left",
3352 "xloc": [
3557 - "default.handlebars->13->233"
3353 + "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1"
3354 ]
3355 },
3356 {
3561 - "en": "Add Intel&reg; AMT CIRA device",
3357 + "en": "Server actions",
3358 "xloc": [
3563 - "default.handlebars->13->235"
3359 + "default.handlebars->container->column_l->p6->p2ServerActions->1->0"
3360 ]
3361 },
3362 {
3567 - "en": "Invitation Type",
3363 + "en": "meshagents?script=1 --no-check-certificate -O ./meshinstall.sh || wget https://",
3364 "xloc": [
3569 - "default.handlebars->13->236"
3365 + "agentinvite.handlebars->3->25",
3366 + "agentinvite.handlebars->3->30"
3367 ]
3368 },
3369 {
3573 - "en": "Invite someone to install the mesh agent. An email with be sent with the link to the mesh agent installation for the \\\"{0}\\\" device group.",
3370 + "en": "To add a new Intel&reg; AMT device to device group \\\"{0}\\\" with CIRA, load the following certificate as trusted root within Intel AMT",
3371 "xloc": [
3575 - "default.handlebars->13->237"
3372 + "default.handlebars->13->221"
3373 ]
3374 },
3375 {
3579 - "en": "Name (optional)",
3376 + "en": "100%",
3377 "xloc": [
3581 - "default.handlebars->13->238"
3378 + "default.handlebars->container->dialog->dialogBody->dialog7->d7meshkvm->5->d7bitmapscaling->1",
3379 + "default-mobile.handlebars->dialog->3->dialog7->d7meshkvm->5->d7bitmapscaling->1"
3380 ]
3381 },
3382 {
3585 - "en": "Email",
3383 + "en": "Download console text",
3384 "xloc": [
3587 - "default.handlebars->13->239",
3588 - "default.handlebars->13->1155",
3589 - "default.handlebars->13->1188",
3590 - "default.handlebars->13->1189",
3591 - "default.handlebars->13->1215",
3592 - "default-mobile.handlebars->9->34"
3385 + "default.handlebars->container->column_l->p15->consoleTable->1->0->1->1"
3386 ]
3387 },
3388 {
3596 - "en": "example@email.com",
3389 + "en": "To get started,",
3390 "xloc": [
3598 - "default.handlebars->13->240"
3391 + "default.handlebars->container->column_l->p1->NoMeshesPanel->1->1->0->3->getStarted1"
3392 ]
3393 },
3394 {
3602 - "en": "Send installation link",
3395 + "en": "Logout",
3396 "xloc": [
3604 - "default.handlebars->13->242"

This file is too large to show in full.

views/default-mobile.handlebars
+17 -8
@@ -1216,9 +1216,9 @@
1216 function account_showChangePassword() {
1217 if (xxdialogMode) return false;
1218 var x = '<table style=margin-left:10px>';
1219 - x += '<tr><td align=right>' + "Old&nbsp;password:" + '</td><td><input id=apassword0 type=password name=apassword0 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b></b></td></tr>';
1220 - x += '<tr><td align=right>' + "New&nbsp;password:" + '</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td></tr>';
1221 - x += '<tr><td align=right>' + "New&nbsp;password:" + '</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>';
1219 + x += '<tr><td align=right>' + nobreak("Old password:") + '</td><td><input id=apassword0 type=password name=apassword0 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b></b></td></tr>';
1220 + x += '<tr><td align=right>' + nobreak("New password:") + '</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td></tr>';
1221 + x += '<tr><td align=right>' + nobreak("New password:") + '</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>';
1222 if (features & 0x00010000) { x += '<tr><td align=right>' + "Password hint:" + '</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>'; }
1223 x += '</table>'
1224 if (passRequirements) {
@@ -1404,7 +1404,7 @@
1404
1405 // Figure out the date
1406 //var fdatestr = '';
1407 - //if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + "/" + (fdate.getDate()) + "/" + fdate.getFullYear() + " " + printTime(fdate) + "&nbsp;"; }
1407 + //if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + '/' + (fdate.getDate()) + '/' + fdate.getFullYear() + ' ' + printTime(fdate) + '&nbsp;'; }
1408
1409 // Figure out the size
1410 var fsize = '';
@@ -1444,10 +1444,18 @@
1444 p5setActions();
1445 }
1446
1447 + function getNiceSize(bytes) {
1448 + if (bytes <= 0) return "Storage exceed";
1449 + if (bytes < 2048) return format("{0}b left", bytes);
1450 + if (bytes < 2097152) return format("{0}k left", Math.round(bytes / 1024));
1451 + if (bytes < 2147483648) return format("{0}m left", Math.round(bytes / 1024 / 1024));
1452 + return format("{0}g left", Math.round(bytes / 1024 / 1024 / 1024));
1453 + }
1454 +
1455 function p5getQuotabar(f) {
1456 while (f.t > 1 && f.t != 4) { f = f.parent; }
1457 if ((f.t != 1 && f.t != 4) || (f.maxbytes == null)) return '';
1450 - return getNiceSize(tq) + ' <progress style=height:10px;width:100px value=' + f.s + ' max=' + f.maxbytes + ' />';
1458 + return getNiceSize(f.maxbytes - f.s) + ' <progress style=height:10px;width:100px value=' + f.s + ' max=' + f.maxbytes + ' />';
1459 }
1460
1461 function p5showPublicLink(u) { setDialogMode(2, "Public Link", 1, null, '<input type=text style=width:100% value="' + u + '" readonly />'); }
@@ -1881,8 +1889,8 @@
1889 // Attribute: Intel AMT
1890 if (node.intelamt != null) {
1891 var str = '';
1884 - var provisioningStates = { 0: "Not&nbsp;Activated&nbsp;(Pre)", 1: "Not&nbsp;Activated&nbsp;(In)", 2: "Activated" };
1885 - if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>' + "Unknown&nbsp;State" + '</i>, v' + node.intelamt.ver; } else
1892 + var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activated") };
1893 + if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>' + nobreak("Unknown State") + '</i>, v' + node.intelamt.ver; } else
1894
1895 if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '<i>' + "Activated" + '</i>'; }
1896 else if ((node.intelamt.ver == null) || (node.intelamt.state == null)) { str += '<i>' + "Unknown Version & State" + '</i>'; }
@@ -1896,7 +1904,7 @@
1904 if (node.intelamt.state == 2) {
1905 if (node.intelamt.user == null || node.intelamt.user == '') {
1906 if ((meshrights & 4) != 0) {
1899 - str += ', <i style=color:#FF0000;cursor:pointer onclick=editDeviceAmtSettings("' + node._id + '")>' + "No&nbsp;Credentials" + '</i>';
1907 + str += ', <i style=color:#FF0000;cursor:pointer onclick=editDeviceAmtSettings("' + node._id + '")>' + nobreak("No Credentials") + '</i>';
1908 } else {
1909 str += ', <i style=color:#FF0000>' + "No Credentials" + '</i>';
1910 }
@@ -3366,6 +3374,7 @@
3374 function printTime(d) { return d.toLocaleTimeString(args.locale); }
3375 function printDateTime(d) { return d.toLocaleString(args.locale); }
3376 function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
3377 + function nobreak(x) { return x.split(' ').join('&nbsp;'); }
3378
3379 </script>
3380 </body>
views/default.handlebars
+34 -33
@@ -1454,7 +1454,7 @@
1454 QH('p41traceStatus', EscapeHtml(message.traceSources.join(', ')));
1455 } else {
1456 serverTraceSources = [];
1457 - QH('p41traceStatus', 'None');
1457 + QH('p41traceStatus', "None");
1458 }
1459 }
1460 break;
@@ -2267,7 +2267,7 @@
2267 QH('p41traceStatus', EscapeHtml(message.event.traceSources.join(', ')));
2268 } else {
2269 serverTraceSources = [];
2270 - QH('p41traceStatus', 'None');
2270 + QH('p41traceStatus', "None");
2271 }
2272 }
2273 break;
@@ -2584,7 +2584,7 @@
2584 deviceHeaderSet();
2585 var extra = '';
2586 if (view == 2) { r += '<tr><td colspan=5>'; }
2587 - if (meshes[node.meshid].mtype == 1) { extra = '<span class=devHeaderx>, Intel&reg; AMT only</span>'; }
2587 + if (meshes[node.meshid].mtype == 1) { extra = '<span class=devHeaderx>' + ", Intel&reg; AMT only" + '</span>'; }
2588 if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
2589 if (view == 2) { r += '<div>'; }
2590 r += '<div class=DevSt style=width:100%;padding-top:4px><span style=float:right>';
@@ -2836,7 +2836,7 @@
2836
2837 function getUserShortStr(node) {
2838 if (node == null || node.users == null || node.users.length == 0) return '';
2839 - if (node.users.length > 1) { return '<span title="' + EscapeHtml(node.users.join(', ')) + '">' + format("{0}&nbsp;users", node.users.length) + '</span>'; }
2839 + if (node.users.length > 1) { return '<span title="' + EscapeHtml(node.users.join(', ')) + '">' + nobreak(format("{0} users", node.users.length)) + '</span>'; }
2840 var u = node.users[0], su = u, i = u.indexOf('\\');
2841 if (i > 0) { su = u.substring(i + 1); }
2842 su = EscapeHtml(su);
@@ -3202,8 +3202,8 @@
3202 var portStr = (serverinfo.port == 443)?'':(':' + serverinfo.port);
3203 if ((features & 0x2000) == 0)
3204 {
3205 - 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 -E ./meshinstall.sh https://' + servername + portStr + domainUrlNoSlash + ' \'' + meshid.split('/')[2] + '\'\r\n';
3206 - 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';
3205 + 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 -E ./meshinstall.sh https://' + servername + portStr + domainUrlNoSlash + ' \'' + meshid.split('/')[2] + '\'\r\n';
3206 + 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';
3207 }
3208 else
3209 {
@@ -4231,7 +4231,7 @@
4231 // Attribute: Intel AMT
4232 if (node.intelamt != null) {
4233 var str = '';
4234 - var provisioningStates = { 0: "Not Activated (Pre)", 1: "Not Activated (In)", 2: "Activated" };
4234 + var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activated") };
4235 if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>' + "Unknown State" + '</i>, v' + node.intelamt.ver; } else
4236
4237 if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '<i>' + "Activated" + '</i>'; }
@@ -4242,7 +4242,7 @@
4242 str += (', v' + node.intelamt.ver);
4243 }
4244
4245 - if (node.intelamt.tls == 1) { str += ', <span title=\"' + "Intel AMT is setup with TLS network security" + '\">' + "TLS" + '</span>'; }
4245 + if (node.intelamt.tls == 1) { str += ', <span title=\"' + "Intel AMT is setup with TLS network security" + '\">' + "TLS" + '</span>'; }
4246 if (node.intelamt.state == 2) {
4247 if (node.intelamt.user == null || node.intelamt.user == '') {
4248 if ((meshrights & 4) != 0) {
@@ -4456,14 +4456,14 @@
4456
4457 function writeDeviceEvent(nodeid) {
4458 if (xxdialogMode) return;
4459 - setDialogMode(2, "Add Device Event", 3, writeDeviceEventEx, '<textarea id=d2devEvent style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea><span style=font-size:10px>This will add an entry to this device\'s event log.<span>', nodeid);
4459 + setDialogMode(2, "Add Device Event", 3, writeDeviceEventEx, '<textarea id=d2devEvent style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea><span style=font-size:10px>' + "This will add an entry to this device\'s event log." + '<span>', nodeid);
4460 }
4461
4462 function writeDeviceEventEx(buttons, tag) { meshserver.send({ action: 'setDeviceEvent', nodeid: decodeURIComponent(tag), msg: encodeURIComponent(Q('d2devEvent').value) }); }
4463
4464 function showNotes(readonly, noteid) {
4465 if (xxdialogMode) return;
4466 - 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);
4466 + 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);
4467 meshserver.send({ action: 'getNotes', id: decodeURIComponent(noteid) });
4468 }
4469
@@ -4595,7 +4595,7 @@
4595 ++count;
4596 date = new Date(date.getTime() - (1000 * 60 * 60 * 24)); // Substract one day
4597 }
4598 - 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>');
4598 + 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>');
4599 }
4600
4601 // Return a color for the given power state
@@ -6643,7 +6643,7 @@
6643
6644 // Save console text to file
6645 function p15downloadConsoleText() {
6646 - saveAs(new Blob([Q('p15agentConsoleText').innerText], { type: "application/octet-stream" }), "console.txt");
6646 + saveAs(new Blob([Q('p15agentConsoleText').innerText], { type: 'application/octet-stream' }), "console.txt");
6647 }
6648
6649 // Called then user presses the "Change Core" button
@@ -6879,9 +6879,9 @@
6879 x += '<br /><br />';
6880 //x += "<form action='" + domainUrl + "changepassword' method=post>";
6881 x += '<table style=margin-left:60px>';
6882 - x += '<tr><td align=right>' + "Old password:" + '</td><td><input id=apassword0 type=password name=apassword0 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b></b></td></tr>';
6883 - x += '<tr><td align=right>' + "New password:" + '</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td></tr>';
6884 - x += '<tr><td align=right>' + "New password:" + '</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>';
6882 + x += '<tr><td align=right>' + nobreak("Old password:") + '</td><td><input id=apassword0 type=password name=apassword0 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b></b></td></tr>';
6883 + x += '<tr><td align=right>' + nobreak("New password:") + '</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td></tr>';
6884 + x += '<tr><td align=right>' + nobreak("New password:") + '</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>';
6885 if (features & 0x00010000) { x += '<tr><td align=right>' + "Password hint:" + '</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>'; }
6886 x += '</table>'
6887 if (passRequirements) {
@@ -7136,7 +7136,7 @@
7136 x += addHtmlValue("Intel&reg; AMT", addLinkConditional(intelAmtPolicy, 'p20editMeshAmt()', meshrights & 1));
7137
7138 // Display group note support
7139 - if (meshrights & 1) { x += '<br><input type=button value=Notes title=\"' + "View notes about this device group" + '\" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />'; }
7139 + if (meshrights & 1) { x += '<br><input type=button value=' + "Notes" + ' title=\"' + "View notes about this device group" + '\" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />'; }
7140
7141 x += '<br style=clear:both><br>';
7142 var currentMeshLinks = currentMesh.links[userinfo._id];
@@ -7174,8 +7174,8 @@
7174 for (var i in sortedusers) {
7175 var trash = '', rights = "Partial Rights", r = sortedusers[i].rights;
7176 if (r == 0xFFFFFFFF) rights = "Full Administrator"; else if (r == 0) rights = "No Rights";
7177 - if ((sortedusers[i].id != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = '<a href=# onclick=\'return p20deleteUser(event,"' + encodeURIComponent(sortedusers[i].id) + '")\' title="Remote user rights to this device group" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
7178 - x += '<tr tabindex=0 onclick=p20viewuser("' + encodeURIComponent(sortedusers[i].id) + '") onkeypress="if (event.key==\'Enter\') p20viewuser(\'' + encodeURIComponent(sortedusers[i].id) + '\')" style=cursor:pointer' + (((count % 2) == 0) ? ';background-color:#DDD' : '') + '><td><div title="User" class=m2></div><div>&nbsp;' + EscapeHtml(decodeURIComponent(sortedusers[i].name)) + '<div></div></div></td><td><div style=float:right>' + trash + '</div><div>' + rights + '</div></td></tr>';
7177 + if ((sortedusers[i].id != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = '<a href=# onclick=\'return p20deleteUser(event,"' + encodeURIComponent(sortedusers[i].id) + '")\' title=\"' + "Remove user rights to this device group" + '\" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
7178 + x += '<tr tabindex=0 onclick=p20viewuser("' + encodeURIComponent(sortedusers[i].id) + '") onkeypress="if (event.key==\'Enter\') p20viewuser(\'' + encodeURIComponent(sortedusers[i].id) + '\')" style=cursor:pointer' + (((count % 2) == 0) ? ';background-color:#DDD' : '') + '><td><div title=\"' + "User" + '\" class=m2></div><div>&nbsp;' + EscapeHtml(decodeURIComponent(sortedusers[i].name)) + '<div></div></div></td><td><div style=float:right>' + trash + '</div><div>' + rights + '</div></td></tr>';
7179 ++count;
7180 }
7181
@@ -7279,8 +7279,8 @@
7279
7280 function p20editmesh(focus) {
7281 if (xxdialogMode) return;
7282 - var x = addHtmlValue('Name', '<input id=dp20meshname style=width:230px maxlength=32 onchange=p20editmeshValidate() onkeyup=p20editmeshValidate(event) />');
7283 - x += addHtmlValue('Description', '<div style=width:230px;margin:0;padding:0><textarea id=dp20meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
7282 + var x = addHtmlValue("Name", '<input id=dp20meshname style=width:230px maxlength=32 onchange=p20editmeshValidate() onkeyup=p20editmeshValidate(event) />');
7283 + x += addHtmlValue("Description", '<div style=width:230px;margin:0;padding:0><textarea id=dp20meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
7284 setDialogMode(2, "Edit Device Group", 3, p20editmeshEx, x);
7285 Q('dp20meshname').value = currentMesh.name;
7286 if (currentMesh.desc) Q('dp20meshdesc').value = currentMesh.desc;
@@ -7678,9 +7678,9 @@
7678 function getNiceSize(bytes) {
7679 if (bytes <= 0) return "Storage limit exceed";
7680 if (bytes < 2048) return format("{0} bytes remaining", bytes);
7681 - if (bytes < 2097152) return format('{0} kilobytes remaining', Math.round(bytes / 1024));
7682 - if (bytes < 2147483648) return format('{0} megabytes remaining', Math.round(bytes / 1024 / 1024));
7683 - return format('{0} gigabytes remaining', Math.round(bytes / 1024 / 1024 / 1024));
7681 + if (bytes < 2097152) return format("{0} kilobytes remaining", Math.round(bytes / 1024));
7682 + if (bytes < 2147483648) return format("{0} megabytes remaining", Math.round(bytes / 1024 / 1024));
7683 + return format("{0} gigabytes remaining", Math.round(bytes / 1024 / 1024 / 1024));
7684 }
7685
7686 function getNiceSize2(bytes) {
@@ -7981,7 +7981,7 @@
7981
7982 // Display the users using the sorted list
7983 var x = '<table class=p3usersTable cellpadding=0 cellspacing=0>', addHeader = true;
7984 - x += '<th>' + "Name" + '<th style=width:80px>Groups<th style=width:120px>' + "Last&nbsp;Access" + '<th style=width:120px>' + "Permissions";
7984 + x += '<th>' + "Name" + '<th style=width:80px>Groups<th style=width:120px>' + nobreak("Last Access") + '<th style=width:120px>' + "Permissions";
7985
7986 // Online users
7987 for (var i in sortedUserIds) {
@@ -8036,7 +8036,7 @@
8036 msg = '<span style=float:right;margin-top:1px;margin-right:4px title=' + "Chat" + '><a href=# onclick=userChat(event,\"" + encodeURIComponent(user._id) + "\",\"" + encodeURIComponent(user.name) + "\")><img src=\'images/icon-chat.png\' height=16 width=16 style=padding-top:2px /></a></span>';
8037 msg += '<span style=float:right;margin-top:1px;margin-left:4px;margin-right:4px title=Notify><a href=# onclick=\'return showUserAlertDialog(event,\"" + encodeURIComponent(user._id) + "\")\'><img src=\'images/icon-notify.png\' height=16 width=16 style=padding-top:2px /></a></span>';
8038 }
8039 - if (sessions == 1) { lastAccess += "1&nbsp;session"; } else { lastAccess += format("{0}&nbsp;sessions", sessions); }
8039 + if (sessions == 1) { lastAccess += nobreak("1 session"); } else { lastAccess += nobreak(format("{0} sessions", sessions)); }
8040 } else {
8041 if (user.login) { lastAccess += '<span title=\"' + format("Last login: {0}", printDateTime(new Date(user.login * 1000))) + '\">' + printDate(new Date(user.login * 1000)) + '</span>'; }
8042 }
@@ -8868,12 +8868,12 @@
8868 function setupGeneralServerStats() {
8869 window.serverStatCpu = new Chart(document.getElementById('serverCpuChart').getContext('2d'), {
8870 type: 'doughnut',
8871 - data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ['Used', 'Free'] },
8871 + data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ["Used", "Free"] },
8872 options: { responsive: true, legend: { position: 'none', }, animation: { animateScale: true, animateRotate: true }, width: '60px' }
8873 });
8874 window.serverStatMemory = new Chart(document.getElementById('serverMemoryChart').getContext('2d'), {
8875 type: 'doughnut',
8876 - data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ['Used', 'Free'] },
8876 + data: { datasets: [{ data: [0, 0], backgroundColor: ['#AAAAAA', '#00AA00'] }], labels: ["Used", "Free"] },
8877 options: { responsive: true, legend: { position: 'none', }, animation: { animateScale: true, animateRotate: true }, width: '60px' }
8878 });
8879 }
@@ -8893,7 +8893,7 @@
8893 }
8894 if ((typeof message.totalmem == 'number') && (typeof message.freemem == 'number')) {
8895 window.serverStatMemory.config.data.datasets[0].data = [message.totalmem - message.freemem, message.freemem];
8896 - QH('serverMemoryChartText', '<div style=margin-bottom:5px>Memory</div><div><b>' + getNiceSize2(message.freemem) + '</b> ' + "free" + ', <b>' + getNiceSize2(message.totalmem) + '</b> ' + "total" + '</div>');
8896 + QH('serverMemoryChartText', '<div style=margin-bottom:5px>' + "Memory" + '</div><div><b>' + getNiceSize2(message.freemem) + '</b> ' + "free" + ', <b>' + getNiceSize2(message.totalmem) + '</b> ' + "total" + '</div>');
8897 QS('serverMemoryChartView')['display'] = 'inline-block';
8898 window.serverStatMemory.update();
8899 }
@@ -8973,11 +8973,11 @@
8973 data = {
8974 labels: [pastDate(0), timeAfter],
8975 datasets: [
8976 - { label: 'Agents', data: [], backgroundColor: 'rgba(158, 151, 16, .1)', borderColor: 'rgb(158, 151, 16)', fill: true },
8977 - { label: 'Users', data: [], backgroundColor: 'rgba(16, 84, 158, .1)', borderColor: 'rgb(16, 84, 158)', fill: true },
8978 - { label: 'User Sessions', data: [], backgroundColor: 'rgba(255, 99, 132, .1)', borderColor: 'rgb(255, 99, 132)', fill: true },
8979 - { label: 'Relay Sessions', data: [], backgroundColor: 'rgba(39, 158, 16, .1)', borderColor: 'rgb(39, 158, 16)', fill: true },
8980 - { label: 'Intel AMT', data: [], backgroundColor: 'rgba(134, 16, 158, .1)', borderColor: 'rgb(134, 16, 158)', fill: true }
8976 + { label: "Agents", data: [], backgroundColor: 'rgba(158, 151, 16, .1)', borderColor: 'rgb(158, 151, 16)', fill: true },
8977 + { label: "Users", data: [], backgroundColor: 'rgba(16, 84, 158, .1)', borderColor: 'rgb(16, 84, 158)', fill: true },
8978 + { label: "User Sessions", data: [], backgroundColor: 'rgba(255, 99, 132, .1)', borderColor: 'rgb(255, 99, 132)', fill: true },
8979 + { label: "Relay Sessions", data: [], backgroundColor: 'rgba(39, 158, 16, .1)', borderColor: 'rgb(39, 158, 16)', fill: true },
8980 + { label: "Intel AMT", data: [], backgroundColor: 'rgba(134, 16, 158, .1)', borderColor: 'rgb(134, 16, 158)', fill: true }
8981 ]
8982 };
8983 for (var i = 0; i < serverTimelineStats.length; i++) {
@@ -9302,6 +9302,7 @@
9302 function printDateTime(d) { return d.toLocaleString(args.locale); }
9303 function addDetailItem(title, value, state) { return '<div><span style=float:right>' + value + '</span><span>' + title + '</span></div>'; }
9304 function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
9305 + function nobreak(x) { return x.split(' ').join('&nbsp;'); }
9306
9307 </script>
9308 </body>
views/translations/agentinvite_fr.handlebars new
+294
@@ -0,0 +1,294 @@
1 +<!DOCTYPE html><html><head>
2 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
3 + <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
4 + <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
5 + <meta name="apple-mobile-web-app-capable" content="yes">
6 + <meta name="format-detection" content="telephone=no">
7 + <link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
8 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
9 + <title>MeshCentral - Agent Installation</title>
10 + <style>
11 + .tab {
12 + overflow: hidden;
13 + border: 1px solid #ccc;
14 + background-color: #f1f1f1;
15 + }
16 +
17 + .tab button {
18 + background-color: inherit;
19 + float: left;
20 + border: none;
21 + outline: none;
22 + cursor: pointer;
23 + padding: 14px 16px;
24 + transition: 0.3s;
25 + }
26 +
27 + .tab button:hover {
28 + background-color: #ddd;
29 + }
30 +
31 + .tab button.active {
32 + background-color: #8f8;
33 + }
34 +
35 + .tabcontent {
36 + display: none;
37 + padding: 6px 12px;
38 + border: 1px solid #ccc;
39 + border-top: none;
40 + }
41 +
42 + </style>
43 +</head>
44 +<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" style="display:none;overflow:hidden">
45 + <div id="container">
46 + <!-- Begin Masthead -->
47 + <div id="masthead" class="noselect" style="background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden;">
48 + <div style="float:left; height: 66px; color:#c8c8c8; padding-left:20px; padding-top:8px">
49 + <strong><font style="font-size:46px; font-family: Arial, Helvetica, sans-serif;">{{{title}}}</font></strong>
50 + </div>
51 + <div style="float:left; height: 66px; color:#c8c8c8; padding-left:5px; padding-top:14px">
52 + <strong><font style="font-size:14px; font-family: Arial, Helvetica, sans-serif;">{{{title2}}}</font></strong>
53 + </div>
54 + <p id="logoutControl" style="color:white;font-size:11px;margin: 10px 10px 0;">{{{logoutControl}}}</p>
55 + </div>
56 + <div id="page_leftbar">
57 + <div style="height:16px"></div>
58 + </div>
59 + <div id="topbar" class="noselect style3" style="height:24px;position:relative">
60 + <div id="uiMenuButton" title="User interface selection" onclick="showUserInterfaceSelectMenu()">
61 + ♦
62 + <div id="uiMenu" style="display:none">
63 + <div id="uiViewButton1" class="uiSelector" onclick="userInterfaceSelectMenu(1)" title="Left bar interface"><div class="uiSelector1"></div></div>
64 + <div id="uiViewButton2" class="uiSelector" onclick="userInterfaceSelectMenu(2)" title="Top bar interface"><div class="uiSelector2"></div></div>
65 + <div id="uiViewButton3" class="uiSelector" onclick="userInterfaceSelectMenu(3)" title="Fixed width interface"><div class="uiSelector3"></div></div>
66 + <div id="uiViewButton4" class="uiSelector" onclick="toggleNightMode()" title="Basculer mode nuit"><div class="uiSelector4"></div></div>
67 + </div>
68 + </div>
69 + </div>
70 + <div id="column_l" style="max-height:calc(100vh - 135px);overflow-y:auto">
71 + <h1>Remote Agent Installation<span id="groupname"></span></h1>
72 + <p>
73 + You have been invited to install a software that will allow a remote operator to fully access your computer remotely including the desktop and files.
74 + Only follow the instructions below if this invitation was expected and you know who will be accessing your computer.
75 + Selecting your operation system and follow the instructions below.
76 + </p>
77 + <div>
78 + <div class="tab">
79 + <button id="twintab64" class="tablinks" onclick="openTab(event, 'wintab64')">Windows 64bit</button>
80 + <button id="twintab32" class="tablinks" onclick="openTab(event, 'wintab32')">Windows 32bit</button>
81 + <button id="tlinuxtab" class="tablinks" onclick="openTab(event, 'linuxtab')">Linux</button>
82 + <button id="tmacostab" class="tablinks" onclick="openTab(event, 'macostab')">MacOS</button>
83 + </div>
84 +
85 + <div id="wintab64" class="tabcontent" style="background-color:white;color:black">
86 + <h3>Microsoft™ Windows 64bit</h3>
87 + <p><a id="win64url">Download the software here</a>, run it and press "Install" or "Connect".</p>
88 + <div style="text-align:center">
89 + <img class="winagent-img" src="images/winagent.png">
90 + </div>
91 + </div>
92 +
93 + <div id="wintab32" class="tabcontent" style="background-color:white;color:black">
94 + <h3>Microsoft™ Windows 32bit</h3>
95 + <p><a id="win32url">Download the software here</a>, run it and press "Install" or "Connect".</p>
96 + <div style="text-align:center">
97 + <img class="winagent-img" src="images/winagent.png">
98 + </div>
99 + </div>
100 +
101 + <div id="linuxtab" class="tabcontent" style="background-color:white;color:black">
102 + <h3>Linux</h3>
103 + <p>To install, cut and paste the following command in a root terminal.</p>
104 + <div id="linuxinstall" style="font-family:courier,'courier new',monospace;margin-left:30px"></div>
105 + <input type="button" value="Copy to clipboard" style="margin-left:30px;margin-top:4px" onclick="copyToClipLinuxInstall()">
106 + <p>To uninstall, cut and paste the following command as root.</p>
107 + <div id="unlinuxinstall" style="font-family:courier,'courier new',monospace;margin-left:30px"></div>
108 + <input type="button" value="Copy to clipboard" style="margin-left:30px;margin-top:4px" onclick="copyToClipLinuxUnInstall()">
109 + <br><br>
110 + </div>
111 +
112 + <div id="macostab" class="tabcontent" style="background-color:white;color:black">
113 + <h3>Apple™ MacOS</h3>
114 + <p><a id="macosurl">Download the installer here</a>, right click on it or press "control" and click on the file. Then select "Open" and follow the instructions.</p>
115 + <div style="text-align:center">
116 + <img src="images/macosagent.png">
117 + </div>
118 + </div>
119 + </div>
120 + </div>
121 + <div id="footer">
122 + <table cellpadding="0" cellspacing="10" style="width: 100%">
123 + <tbody><tr>
124 + <td style="text-align:left"></td>
125 + <td style="text-align:right"></td>
126 + </tr>
127 + </tbody></table>
128 + </div>
129 + </div>
130 + <script>
131 + 'use strict';
132 + var uiMode = parseInt(getstore('uiMode', 1));
133 + var webPageStackMenu = false;
134 + var webPageFullScreen = true;
135 + var nightMode = (getstore('_nightMode', '0') == '1');
136 + var domain = "{{{domain}}}";
137 + var domainUrl = "{{{domainurl}}}";
138 + var meshid = "{{{meshid}}}";
139 + var serverPort = "{{{serverport}}}";
140 + var serverHttps = "{{{serverhttps}}}";
141 + var serverNoProxy = "{{{servernoproxy}}}";
142 + var installFlags = "{{{installflags}}}";
143 + var groupName = decodeURIComponent("{{{meshname}}}");
144 + if (groupName != '') { QH('groupname', ' for ' + groupName); }
145 + userInterfaceSelectMenu();
146 + setup();
147 +
148 + // Toggle user interface menu
149 + function showUserInterfaceSelectMenu() {
150 + Q('uiViewButton1').classList.remove('uiSelectorSel');
151 + Q('uiViewButton2').classList.remove('uiSelectorSel');
152 + Q('uiViewButton3').classList.remove('uiSelectorSel');
153 + Q('uiViewButton4').classList.remove('uiSelectorSel');
154 + try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
155 + QV('uiMenu', (QS('uiMenu').display == 'none'));
156 + if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
157 + }
158 +
159 + function userInterfaceSelectMenu(s) {
160 + if (s) { uiMode = s; putstore('uiMode', uiMode); }
161 + webPageFullScreen = (uiMode < 3);
162 + webPageStackMenu = true;//(uiMode > 1);
163 + toggleFullScreen(0);
164 + toggleStackMenu(0);
165 + QC('column_l').add('room4submenu');
166 + }
167 +
168 + function toggleNightMode() {
169 + nightMode = !nightMode;
170 + if (nightMode) { QC('body').add('night'); } else { QC('body').remove('night'); }
171 + putstore('_nightMode', nightMode ? '1' : '0');
172 + }
173 +
174 + // Toggle the web page to full screen
175 + function toggleFullScreen(toggle) {
176 + if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
177 + var hide = 0;
178 + //if (args.hide) { hide = parseInt(args.hide); }
179 + if (webPageFullScreen == false) {
180 + QC('body').remove("menu_stack");
181 + QC('body').remove("fullscreen");
182 + QC('body').remove("arg_hide");
183 + //if (xxcurrentView >= 10) QC('column_l').add('room4submenu');
184 + //QV('UserDummyMenuSpan', false);
185 + //QV('page_leftbar', false);
186 + } else {
187 + QC('body').add("fullscreen");
188 + if (hide & 16) QC('body').add("arg_hide"); // This is replacement for QV('page_leftbar', !(hide & 16));
189 + //QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
190 + //QV('page_leftbar', true);
191 + }
192 + QV('body', true);
193 + }
194 +
195 + // If FullScreen, toggle menu to be horisontal or vertical
196 + function toggleStackMenu(toggle) {
197 + if (webPageFullScreen == true) {
198 + if (toggle === 1) {
199 + webPageStackMenu = !webPageStackMenu;
200 + putstore('webPageStackMenu', webPageStackMenu);
201 + }
202 + if (webPageStackMenu == false) {
203 + QC('body').remove("menu_stack");
204 + } else {
205 + QC('body').add("menu_stack");
206 + //if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
207 + }
208 + }
209 + }
210 +
211 + function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
212 + function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
213 +
214 + function openTab(evt, tabname) {
215 + // Declare all variables
216 + var i, tabcontent, tablinks;
217 +
218 + // Get all elements with class="tabcontent" and hide them
219 + tabcontent = document.getElementsByClassName("tabcontent");
220 + for (i = 0; i < tabcontent.length; i++) {
221 + tabcontent[i].style.display = "none";
222 + }
223 +
224 + // Get all elements with class="tablinks" and remove the class "active"
225 + tablinks = document.getElementsByClassName("tablinks");
226 + for (i = 0; i < tablinks.length; i++) {
227 + tablinks[i].className = tablinks[i].className.replace("actif", "");
228 + }
229 +
230 + // Show the current tab, and add an "active" class to the button that opened the tab
231 + document.getElementById(tabname).style.display = "block";
232 + if (evt != null) { evt.currentTarget.className += "actif"; } else { document.getElementById('t' + tabname).className += "actif"; }
233 + }
234 +
235 + var linuxInstall, linuxUnInstall;
236 + function setup() {
237 + var servername = window.location.hostname;
238 + var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
239 +
240 + // Windows 64bit Setup
241 + var url = 'meshagents?id=4&meshid=' + meshid;
242 + if (installFlags != 0) { url += ('&installflags=' + installFlags); }
243 + Q('win64url').href = url;
244 +
245 + // Windows 32bit Setup
246 + url = 'meshagents?id=3&meshid=' + meshid;
247 + if (installFlags != 0) { url += ('&installflags=' + installFlags); }
248 + Q('win32url').href = url;
249 +
250 + // MacOS Setup
251 + url = 'meshosxagent?id=16&meshid=' + meshid;
252 + Q('macosurl').href = url;
253 +
254 + // Linux Setup
255 + if (serverHttps == 1) {
256 + var portStr = (serverPort == 443) ? '' : (":" + serverPort);
257 + if (serverNoProxy == 0) {
258 + linuxInstall = "(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 + "'\r\n";
259 + linuxUnInstall = "(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";
260 + } else {
261 + // Server asked that agent be installed to preferably not use a HTTP proxy.
262 + linuxInstall = "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 + "'\r\n";
263 + linuxUnInstall = "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";
264 + }
265 + } else {
266 + var portStr = (serverPort == 80) ? '' : (":" + serverPort);
267 + if (serverNoProxy == 0) {
268 + linuxInstall = "(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 + "'\r\n";
269 + linuxUnInstall = "(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";
270 + } else {
271 + // Server asked that agent be installed to preferably not use a HTTP proxy.
272 + linuxInstall = "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 + "'\r\n";
273 + linuxUnInstall = "wget http://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
274 + }
275 + }
276 + QH('linuxinstall', linuxInstall);
277 + QH('unlinuxinstall', linuxUnInstall);
278 +
279 + // Attempt to detect the most likely operating system for this browser
280 + if (navigator.userAgent.indexOf('Win64') >= 0) { openTab(null, 'wintab64'); }
281 + else if (navigator.userAgent.indexOf('Windows') >= 0) { openTab(null, 'wintab32'); }
282 + else if (navigator.userAgent.indexOf('Linux') >= 0) { openTab(null, 'linuxtab'); }
283 + else if (navigator.userAgent.indexOf('Macintosh') >= 0) { openTab(null, 'macostab'); }
284 + else { openTab(null, 'wintab64'); }
285 + }
286 +
287 + function copyToClipLinuxInstall() { copyTextToClip(linuxInstall); }
288 + function copyToClipLinuxUnInstall() { copyTextToClip(linuxUnInstall); }
289 + function copyTextToClip(txt) { function selectElementText(e) { if (document.selection) { var range = document.body.createTextRange(); range.moveToElementText(e); range.select(); } else if (window.getSelection) { var range = document.createRange(); range.selectNode(e); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } } var e = document.createElement('DIV'); e.textContent = txt; document.body.appendChild(e); selectElementText(e); document.execCommand('copy'); e.remove(); }
290 +
291 + </script>
292 +
293 +
294 +</body></html>
\ No newline at end of file
views/translations/default-mobile_fr.handlebars new
+3379
@@ -0,0 +1,3379 @@
1 +<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
2 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
3 + <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
4 + <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
5 + <meta name="apple-mobile-web-app-capable" content="yes">
6 + <meta name="format-detection" content="telephone=no">
7 + <link rel="shortcut icon" type="image/x-icon" href="{{{domainurl}}}favicon.ico">
8 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
9 + <script type="text/javascript" src="scripts/meshcentral.js"></script>
10 + <script type="text/javascript" src="scripts/agent-redir-ws-0.1.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-0.2.0.js"></script>
13 + <script type="text/javascript" src="scripts/amt-redir-ws-0.1.0.js"></script>
14 + <script type="text/javascript" src="scripts/amt-desktop-0.0.2.js"></script>
15 + <script type="text/javascript" src="scripts/zlib.js"></script>
16 + <script type="text/javascript" src="scripts/zlib-inflate.js"></script>
17 + <script type="text/javascript" src="scripts/zlib-adler32.js"></script>
18 + <script type="text/javascript" src="scripts/zlib-crc32.js"></script>
19 + <script keeplink="1" type="text/javascript" src="scripts/filesaver.js"></script>
20 + <title>{{{title}}}</title>
21 + <style>
22 + a {
23 + color: #036;
24 + text-decoration: underline;
25 + }
26 +
27 + #footer a {
28 + color: #fff;
29 + text-decoration: underline;
30 + }
31 +
32 + #footer a:hover {
33 + color: #fff;
34 + text-decoration: none;
35 + }
36 +
37 + .i1 {
38 + background: url(../images/icons50.png) 0px 0px;
39 + height: 50px;
40 + width: 50px;
41 + border: none;
42 + }
43 +
44 + .i2 {
45 + background: url(../images/icons50.png) -50px 0px;
46 + height: 50px;
47 + width: 50px;
48 + border: none;
49 + }
50 +
51 + .i3 {
52 + background: url(../images/icons50.png) -100px 0px;
53 + height: 50px;
54 + width: 50px;
55 + border: none;
56 + }
57 +
58 + .i4 {
59 + background: url(../images/icons50.png) -150px 0px;
60 + height: 50px;
61 + width: 50px;
62 + border: none;
63 + }
64 +
65 + .i5 {
66 + background: url(../images/icons50.png) -200px 0px;
67 + height: 50px;
68 + width: 50px;
69 + border: none;
70 + }
71 +
72 + .i6 {
73 + background: url(../images/icons50.png) -250px 0px;
74 + height: 50px;
75 + width: 50px;
76 + border: none;
77 + }
78 +
79 + .m0 {
80 + background: url(../images/images16.png) -32px 0px;
81 + height: 16px;
82 + width: 16px;
83 + border: none;
84 + float: left;
85 + }
86 +
87 + .m1 {
88 + background: url(../images/images16.png) -16px 0px;
89 + height: 16px;
90 + width: 16px;
91 + border: none;
92 + float: left;
93 + }
94 +
95 + .m2 {
96 + background: url(../images/images16.png) -96px 0px;
97 + height: 16px;
98 + width: 16px;
99 + border: none;
100 + float: left;
101 + }
102 +
103 + .m3 {
104 + background: url(../images/images16.png) -112px 0px;
105 + height: 16px;
106 + width: 16px;
107 + border: none;
108 + float: left;
109 + }
110 +
111 + .gray {
112 + /*filter: url("data:image/svg+xml;utf8,&lt;svg xmlns=\'http://www.w3.org/2000/svg\'&gt;&lt;filter id=\'grayscale\'&gt;&lt;feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/&gt;&lt;/filter&gt;&lt;/svg&gt;#grayscale");*/ /* Firefox 10+, Firefox on Android */
113 + filter: gray; /* IE6-9 */
114 + -webkit-filter: grayscale(100%) opacity(60%); /* Chrome 19+, Safari 6+, Safari 6+ iOS */
115 + }
116 +
117 + .DevSt {
118 + padding-left: 5px;
119 + border-bottom-style: solid;
120 + border-bottom-width: 1px;
121 + border-bottom-color: #DDDDDD;
122 + }
123 +
124 + .noselect {
125 + -webkit-touch-callout: none;
126 + -webkit-user-select: none;
127 + -khtml-user-select: none;
128 + -moz-user-select: none;
129 + -ms-user-select: none;
130 + user-select: none;
131 + }
132 +
133 + .fileIcon1 {
134 + background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAPb49Y2Sj9LT2f///yH5BAEAAAMALAAAAAAQABAAAAImnI+py+1vhJwyUYAzHTL4D3qdlJWaIFJqmKod607sDKIiDUP63hQAOw==);
135 + height: 16px;
136 + width: 16px;
137 + cursor: pointer;
138 + border: none;
139 + float: left;
140 + margin-top: 1px;
141 + }
142 +
143 + .fileIcon2 {
144 + background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAM2xV/Xur+XPgP///yH5BAEAAAMALAAAAAAQABAAAAJD3ISZIGHWUGihznesYDYATFVM+D2hJ4lgN1olxALAtAlmPCJvuMmJd6PJckDYwicrHhTD5o7plJmg0Uc0asNMkphHAQA7);
145 + height: 16px;
146 + width: 16px;
147 + cursor: pointer;
148 + border: none;
149 + float: left;
150 + margin-top: 1px;
151 + }
152 +
153 + .fileIcon3 {
154 + background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAPb19IGBgbq6uv///yH5BAEAAAMALAAAAAAQABAAAAIy3ISpxgcPH2ouQgFEw1YmxnUXKEaaEZZnVWZk66JwzKpvuwZzwOgwb/C1gIOA8Yg8DgoAOw==);
155 + height: 16px;
156 + width: 16px;
157 + cursor: pointer;
158 + border: none;
159 + float: left;
160 + margin-top: 1px;
161 + }
162 +
163 + .fileIcon4 {
164 + background: url(../images/meshicon16.png);
165 + height: 16px;
166 + width: 16px;
167 + cursor: pointer;
168 + border: none;
169 + float: left;
170 + margin-top: 1px;
171 + }
172 +
173 + .filelist {
174 + -moz-user-select: none;
175 + -khtml-user-select: none;
176 + -webkit-user-select: none;
177 + -o-user-select: none;
178 + cursor: default;
179 + -khtml-user-drag: element;
180 + background-color: white;
181 + clear: both;
182 + }
183 + </style>
184 +</head>
185 +<body onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;margin:0;padding:0;border:0;color:black;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
186 + <div id="container">
187 + <div id="mastheadx"></div>
188 + <div id="masthead" style="background:url(logo.png) 0px 0px;background-size:341px 50px;background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden">
189 + <div style="width:calc(100% - 50px);overflow:hidden">
190 + <div style="float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:6px">
191 + <strong><font style="font-size:36px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
192 + </div>
193 + <div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:10px">
194 + <strong><font style="font-size:12px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
195 + </div>
196 + </div>
197 + <img id="topMenuIcon" class="noselect" style="position:absolute;right:0;top:10px;bottom:50px;color:#c8c8c8;font-size:44px;margin-right:8px;cursor:pointer;display:none" onclick="topMenu()" src="/images/3bars-30.png" width="30" height="30">
198 + </div>
199 + <div id="page_content" style="overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%">
200 + <div id="column_l" style="width:100%;padding:0;position:absolute;bottom:0px;top:0px">
201 + <div id="p0" style="display:none;width:100%;height:100%">
202 + <div style="display:flex;align-items:center;width:100%;height:100%">
203 + <div id="p0message" style="text-align:center;width:100%"><span id="p0span">Server disconnected</span>, <href onclick="reload()" style="cursor:pointer"><u>click to reconnect</u></href>.</div>
204 + </div>
205 + </div>
206 + <div id="p1" style="display:none;width:100%;height:100%">
207 + <div style="display:flex;align-items:center;width:100%;height:100%">
208 + <div id="p1message" style="text-align:center;width:100%"></div>
209 + </div>
210 + </div>
211 + <div id="p2" style="display:none">
212 + <div id="xdevices"></div>
213 + </div>
214 + <div id="p3" style="display:none;position:absolute;bottom:0;top:0;width:100%">
215 + <table cellspacing="0" style="margin:0;padding:0;border-spacing:0;border:0;">
216 + <tbody><tr style="padding:0">
217 + <td style="padding:0;color:#c8c8c8;text-align:center;cursor:pointer" width="60px" valign="top" onclick="goBack()">
218 + <div style="padding:0;background-color:#036;width:10px;height:10px;float:right;border:0">
219 + <div style="background-color:white;width:10px;height:10px;border-radius:10px 0 0 0;border-right:1px solid white;border-bottom:1px solid white"></div>
220 + </div>
221 + <div style="padding:0;font-size:25px;background-color:#036;width:50px;border-radius:0 0 10px 0;height:36px">◀</div>
222 + </td>
223 + <td>
224 + <img src="/images/user-50.png" width="50" height="50">
225 + </td>
226 + <td>
227 + <div style="margin-left:5px">
228 + <strong style="font-size:large"><span id="p3userName"></span></strong><br>
229 + </div>
230 + </td>
231 + </tr>
232 + </tbody></table>
233 + <div id="p3info" style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%">
234 + <div style="margin-left:8px">
235 + <div id="p3AccountActions">
236 + <p><strong>Account Security</strong></p>
237 + <div style="margin-left:9px;margin-bottom:8px">
238 + <div id="manageAuthApp" style="margin-top:5px;display:none"><a onclick="account_manageAuthApp()" style="cursor:pointer">Manage authenticator app</a></div>
239 + <div id="manageOtp" style="margin-top:5px;display:none"><a onclick="account_manageOtp(0)" style="cursor:pointer">Manage backup codes</a></div>
240 + </div>
241 + <p><strong>Account Actions</strong></p>
242 + <div style="margin-left:9px;margin-bottom:8px">
243 + <div style="margin-top:5px"><span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a></span></div>
244 + <div style="margin-top:5px"><span id="changeEmailId" style="display:none"><a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a></span></div>
245 + <div style="margin-top:5px"><a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><span id="p2nextPasswordUpdateTime"></span></div>
246 + <div style="margin-top:5px"><a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a></div>
247 + </div>
248 + <br style="clear:both">
249 + </div>
250 + <strong>Device Groups</strong>
251 + <span id="p3createMeshLink1">( <a onclick="account_createMesh()" style="cursor:pointer"><img src="images/icon-addnew.png" width="12" height="12" border="0"> New</a> )</span>
252 + <br><br>
253 + <div id="p3meshes"></div>
254 + <div id="p3noMeshFound" style="margin-left:9px;display:none">No device groups.<span id="p3createMeshLink2"> <a onclick="account_createMesh()" style="cursor:pointer"><strong>Get started here!</strong></a></span></div>
255 + <br style="clear:both">
256 + </div>
257 + </div>
258 + </div>
259 + <div id="p5" style="display:none">
260 + <table cellspacing="0" style="margin:0;padding:0;border-spacing:0;border:0;">
261 + <tbody><tr style="padding:0">
262 + <td style="padding:0;color:#c8c8c8;text-align:center;cursor:pointer" width="60px" valign="top" onclick="goBack()">
263 + <div style="padding:0;background-color:#036;width:10px;height:10px;float:right;border:0">
264 + <div style="background-color:white;width:10px;height:10px;border-radius:10px 0 0 0;border-right:1px solid white;border-bottom:1px solid white"></div>
265 + </div>
266 + <div style="padding:0;font-size:25px;background-color:#036;width:50px;border-radius:0 0 10px 0;height:36px">◀</div>
267 + </td>
268 + <td>
269 + <img src="/images/user-50.png" width="50" height="50">
270 + </td>
271 + <td>
272 + <div style="margin-left:5px">
273 + <strong style="font-size:large">My Files</strong><br>
274 + </div>
275 + </td>
276 + </tr>
277 + </tbody></table>
278 + <div id="p5myfiles" style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%">
279 + <table id="p5toolbar" style="width:100%;height:78px" cellpadding="0" cellspacing="0">
280 + <tbody><tr>
281 + <td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign="bottom">
282 + <div style="width:100%;text-align:center">
283 + <input type="button" style="width:calc(100%/5 - 5px)" id="p5FolderUp" disabled="disabled" onclick="p5folderup()" value="Up">
284 + <input type="button" style="width:calc(100%/5 - 5px)" id="p5SelectAllButton" disabled="disabled" onclick="p5selectallfile()" value="SelectAll" onkeypress="return false" onkeydown="return false">
285 + <input type="button" style="width:calc(100%/5 - 5px)" id="p5RenameFileButton" disabled="disabled" value="Rename" onclick="p5renamefile()" onkeypress="return false" onkeydown="return false">
286 + <input type="button" style="width:calc(100%/5 - 5px)" id="p5DeleteFileButton" disabled="disabled" value="Delete" onclick="p5deletefile()" onkeypress="return false" onkeydown="return false">
287 + <input type="button" style="width:calc(100%/5 - 5px)" id="p5NewFolderButton" disabled="disabled" value="Folder" onclick="p5createfolder()" onkeypress="return false" onkeydown="return false">
288 + </div>
289 + <div style="width:100%;text-align:center">
290 + <input type="button" style="width:calc(100%/5 - 5px)" id="p5UploadButton" disabled="disabled" value="Télécharger" onclick="p5uploadFile()" onkeypress="return false" onkeydown="return false">
291 + <input type="button" style="width:calc(100%/5 - 5px)" id="p5CutButton" disabled="disabled" value="Cut" onclick="p5copyFile(1)" onkeypress="return false" onkeydown="return false">
292 + <input type="button" style="width:calc(100%/5 - 5px)" id="p5CopyButton" disabled="disabled" value="Copy" onclick="p5copyFile(0)" onkeypress="return false" onkeydown="return false">
293 + <input type="button" style="width:calc(100%/5 - 5px)" id="p5PasteButton" disabled="disabled" value="Paste" onclick="p5pasteFile()" onkeypress="return false" onkeydown="return false">
294 + <input type="button" style="width:calc(100%/5 - 5px)" id="p5RefreshButton" value="Refresh" onclick="p5refreshFiles()" onkeypress="return false" onkeydown="return false">
295 + </div>
296 + </td>
297 + </tr>
298 + <tr>
299 + <td style="background-color:#E4E9E7;height:28px">
300 + <table style="width:100%">
301 + <tbody><tr>
302 + <td id="p5currentpath" style="overflow:hidden;padding-left:4px;padding-top:2px"></td>
303 + <td style="text-align:right;padding-right:4px">
304 + <select id="p5sortdropdown" onchange="updateFiles()">
305 + <option value="1" selected="selected">Sort by name</option>
306 + <option value="2">Sort by size</option>
307 + <option value="3">Sort by date</option>
308 + <option value="4">Descend by name</option>
309 + <option value="5">Descend by size</option>
310 + <option value="6">Descend by date</option>
311 + </select>
312 + </td>
313 + </tr>
314 + </tbody></table>
315 + </td>
316 + </tr>
317 + </tbody></table>
318 + <div id="p5filetable" style="width:100%;height:calc(100% - 133px);overflow:auto;-webkit-user-select:none">
319 + <!--
320 + <div id="p5bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&checkmark;</b></div>
321 + <div id="p5bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&#10007;</b></div>
322 + -->
323 + <span id="p5files"></span>
324 + </div>
325 + <table id="p5toolbarBottom" style="width:100%;height:22px;position:absolute;bottom:0px;background-color:#D3D9D6" cellpadding="0" cellspacing="0">
326 + <tbody><tr>
327 + <td style="text-align:left;padding:3px">&nbsp;<span id="p5bottomstatus"></span></td>
328 + <td id="p5rightOfButtons" style="text-align:right;padding:3px"></td>
329 + </tr>
330 + </tbody></table>
331 + </div>
332 + </div>
333 + <div id="p10" style="display:none;position:absolute;bottom:0;top:0;width:100%;overflow:hidden">
334 + <table cellspacing="0" style="margin:0;padding:0;border-spacing:0;border:0;position:absolute;top:0">
335 + <tbody><tr style="padding:0">
336 + <td style="padding:0;color:#c8c8c8;text-align:center;cursor:pointer" width="60px" valign="top" onclick="goBack()">
337 + <div style="padding:0;background-color:#036;width:10px;height:10px;float:right;border:0">
338 + <div style="background-color:white;width:10px;height:10px;border-radius:10px 0 0 0;border-right:1px solid white;border-bottom:1px solid white"></div>
339 + </div>
340 + <div style="padding:0;font-size:25px;background-color:#036;width:50px;border-radius:0 0 10px 0;height:36px">◀</div>
341 + </td>
342 + <td>
343 + <a id="MainComputerImage" style="cursor:pointer" onclick="p10showiconselector()"></a>
344 + </td>
345 + <td>
346 + <div style="margin-left:5px">
347 + <strong><span id="p10deviceName"></span></strong><br>
348 + <span id="MainComputerState"></span>
349 + </div>
350 + </td>
351 + </tr>
352 + </tbody></table>
353 + <div id="p10general" style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%">
354 + <div id="p10html" style="margin-left:8px;margin-right:8px"></div>
355 + <div id="p10html2"></div>
356 + <div id="p10html3"></div>
357 + </div>
358 + <div id="p10desktop" style="overflow:hidden;position:absolute;top:55px;bottom:0px;width:100%;display:none">
359 + <div id="deskarea1" style="position:absolute;top:0px;width:100%;height:25px">
360 + <div style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
361 + <div style="float:right;text-align:right">
362 + <span id="p14power"></span>&nbsp;
363 + <input id="DeskSoftInput" type="text" style="width:25px;display:none;opacity:.2" onblur="toggleSoftKeys(0)" onkeypress="return ondeskkeypress(event)" onkeydown="return ondeskkeydown(event)" onkeyup="return ondeskkeyup(event)">
364 + </div>
365 + <div style="margin-left:3px">
366 + <input type="button" id="connectbutton1" value="Connect" onclick="connectDesktop(event,1)" onkeypress="return false" onkeydown="return false" disabled="disabled">
367 + <input type="button" id="connectbutton1h" value="HW Connect" onclick="connectDesktop(event,2)" onkeypress="return false" onkeydown="return false" disabled="disabled">
368 + <input type="button" id="disconnectbutton1" value="Disconnect" onclick="connectDesktop(event,0)" onkeypress="return false" onkeydown="return false">
369 + <span id="deskstatus">Disconnected</span>
370 + </div>
371 + </div>
372 + </div>
373 + <div id="deskarea3" style="position:absolute;top:25px;width:100%;height:calc(100% - 50px)">
374 + <div id="deskarea3x" style="background:black;text-align:center;height:100%;position:relative">
375 + <div id="DeskParent" style="height:100%">
376 + <canvas id="Desk" width="640" height="200" style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)" onmousewheel="dmousewheel(event)"></canvas>
377 + </div>
378 + <div id="DeskTools" style="position:absolute;width:400px;height:100%;background-color:gray;top:0;right:0;border-left:2px solid lightgray;display:none">
379 + <a id="DeskToolsRefreshButton" style="float:right;padding:3px;cursor:pointer" onclick="refreshDeskTools()">Refresh</a>
380 + <div id="DeskToolsBar" style="position:absolute;padding:3px;border-radius: 3px 3px 0px 0px;top:5px;left:4px;bottom:26px;background-color:lightgray;cursor:pointer">Processes</div>
381 + <div style="position:absolute;top:26px;left:4px;right:4px;bottom:4px;background-color:lightgray;text-align:left">
382 + <div style="border-bottom:1px solid darkgray;padding:3px"><a style="width:50px;padding-right:5px;float:left;cursor:pointer" onclick="sortProcess(0)">PID</a><a style="cursor:pointer" onclick="sortProcess(1)">Name</a></div>
383 + <div id="DeskToolsProcesses" style="overflow-y:scroll;position:absolute;top:24px;bottom:0px;width:100%"></div>
384 + </div>
385 + </div>
386 + </div>
387 + </div>
388 + <div id="deskarea4" style="position:absolute;bottom:0px;width:100%;height:25px">
389 + <div style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
390 + <div style="float:right;text-align:right">
391 + <select id="termdisplays" style="display:none" onchange="deskSetDisplay(event)" onclick="deskGetDisplayNumbers(event)"></select>&nbsp;
392 + <span id="DeskToastButton"><img src="images/icon-notify.png" onclick="deviceToastFunction()" height="16" width="16" style="padding-top:2px"></span>&nbsp;
393 + <!--<input id=DeskToolsButton type=button value=Tools onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()">&nbsp;-->
394 + </div>
395 + <div>
396 + <input id="deskActionsBtn" type="button" style="margin-left:3px" onkeypress="return false" onkeydown="return false" value="Actions" onclick="deviceActionFunction()">
397 + <input type="button" value="Settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()">
398 + <input type="button" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="display:none">
399 + <input id="DeskSpecialKeys" type="button" value="Special Keys" onkeypress="return false" onkeydown="return false" onclick="sendSpecialKeys()">
400 + <input id="DeskSoftKeys" type="button" value="Keyboard" onkeypress="return false" onkeydown="return false" onclick="toggleSoftKeys(1)">
401 + <label><span id="DeskControlSpan" style="display:none"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false">Input</span></label>
402 + </div>
403 + </div>
404 + </div>
405 + </div>
406 + <div id="p10files" style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%;display:none">
407 + <table id="p13toolbar" style="width:100%;height:111px" cellpadding="0" cellspacing="0">
408 + <tbody><tr>
409 + <td style="background-color:#C0C0C0;border-bottom:2px solid black;padding:2px">
410 + <div style="float:right;text-align:right">
411 + <input id="filesActionsBtn" type="button" onkeypress="return false" onkeydown="return false" value="Actions" onclick="deviceActionFunction()" style="margin-right:2px">
412 + </div>
413 + <div style="margin-left:2px">
414 + <input id="p13AutoConnect" value="AutoConnect" onclick="autoConnectFiles(event)" onkeypress="return false" onkeydown="return false" type="button" style="display:none">
415 + <input id="p13Connect" value="Connect" onclick="connectFiles(event)" onkeypress="return false" onkeydown="return false" type="button">
416 + <span id="p13Status">Disconnected</span>
417 + </div>
418 + </td>
419 + </tr>
420 + <tr>
421 + <td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign="bottom">
422 + <div style="width:100%;text-align:center">
423 + <input type="button" style="width:calc(100%/5 - 5px)" id="p13FolderUp" disabled="disabled" onclick="p13folderup()" value="Up">
424 + <input type="button" style="width:calc(100%/5 - 5px)" id="p13SelectAllButton" disabled="disabled" onclick="p13selectallfile()" value="SelectAll" onkeypress="return false" onkeydown="return false">
425 + <input type="button" style="width:calc(100%/5 - 5px)" id="p13RenameFileButton" disabled="disabled" value="Rename" onclick="p13renamefile()" onkeypress="return false" onkeydown="return false">
426 + <input type="button" style="width:calc(100%/5 - 5px)" id="p13DeleteFileButton" disabled="disabled" value="Delete" onclick="p13deletefile()" onkeypress="return false" onkeydown="return false">
427 + <input type="button" style="width:calc(100%/5 - 5px)" id="p13NewFolderButton" disabled="disabled" value="Folder" onclick="p13createfolder()" onkeypress="return false" onkeydown="return false">
428 + </div>
429 + <div style="width:100%;text-align:center">
430 + <input type="button" style="width:calc(100%/5 - 5px)" id="p13UploadButton" disabled="disabled" value="Télécharger" onclick="p13uploadFile()" onkeypress="return false" onkeydown="return false">
431 + <input type="button" style="width:calc(100%/5 - 5px)" id="p13CutButton" disabled="disabled" value="Cut" onclick="p13copyFile(1)" onkeypress="return false" onkeydown="return false">
432 + <input type="button" style="width:calc(100%/5 - 5px)" id="p13CopyButton" disabled="disabled" value="Copy" onclick="p13copyFile(0)" onkeypress="return false" onkeydown="return false">
433 + <input type="button" style="width:calc(100%/5 - 5px)" id="p13PasteButton" disabled="disabled" value="Paste" onclick="p13pasteFile()" onkeypress="return false" onkeydown="return false">
434 + <input type="button" style="width:calc(100%/5 - 5px)" id="p13RefreshButton" disabled="disabled" value="Refresh" onclick="p13folderup(9999)" onkeypress="return false" onkeydown="return false">
435 + </div>
436 + </td>
437 + </tr>
438 + <tr>
439 + <td style="background-color:#E4E9E7;height:28px">
440 + <table style="width:100%">
441 + <tbody><tr>
442 + <td id="p13currentpath" style="overflow:hidden;padding-left:4px;padding-top:2px"></td>
443 + <td style="text-align:right;padding-right:4px">
444 + <select id="p13sortdropdown" onchange="p13updateFiles()">
445 + <option value="1" selected="selected">Sort by name</option>
446 + <option value="2">Sort by size</option>
447 + <option value="3">Sort by date</option>
448 + <option value="4">Descend by name</option>
449 + <option value="5">Descend by size</option>
450 + <option value="6">Descend by date</option>
451 + </select>
452 + </td>
453 + </tr>
454 + </tbody></table>
455 + </td>
456 + </tr>
457 + </tbody></table>
458 + <div id="p13filetable" style="width:100%;height:calc(100% - 133px);overflow:auto;-webkit-user-select:none">
459 + <!--
460 + <div id="p13bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&checkmark;</b></div>
461 + <div id="p13bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&#10007;</b></div>
462 + -->
463 + <span id="p13files"></span>
464 + </div>
465 + <table id="p13toolbarBottom" style="width:100%;height:22px;position:absolute;bottom:0px" cellpadding="0" cellspacing="0">
466 + <tbody><tr><td style="text-align:left;padding:3px;text-align:center;background-color:#D3D9D6">&nbsp;<span id="p13bottomstatus"></span></td></tr>
467 + </tbody></table>
468 + </div>
469 + </div>
470 + <div id="p20" style="display:none;position:absolute;bottom:0;top:0;width:100%">
471 + <table cellspacing="0" style="margin:0;padding:0;border-spacing:0;border:0;">
472 + <tbody><tr style="padding:0">
473 + <td style="padding:0;color:#c8c8c8;text-align:center;cursor:pointer" width="60px" valign="top" onclick="goBack()">
474 + <div style="padding:0;background-color:#036;width:10px;height:10px;float:right;border:0">
475 + <div style="background-color:white;width:10px;height:10px;border-radius:10px 0 0 0;border-right:1px solid white;border-bottom:1px solid white"></div>
476 + </div>
477 + <div style="padding:0;font-size:25px;background-color:#036;width:50px;border-radius:0 0 10px 0;height:36px">◀</div>
478 + </td>
479 + <td onclick="p20editmesh(1)">
480 + <img src="/images/meshicon50.png" width="50" height="50">
481 + </td>
482 + <td onclick="p20editmesh(1)">
483 + <div style="margin-left:5px">
484 + <strong style="font-size:large"><span id="p20meshName"></span></strong><br>
485 + </div>
486 + </td>
487 + </tr>
488 + </tbody></table>
489 + <div id="p20info" style="margin-left:8px;margin-right:8px"></div>
490 + </div>
491 + </div>
492 + </div>
493 + <div id="footer" style="height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px">
494 + <table id="footerMenu" cellpadding="0" cellspacing="0" style="height:32px;width:100%;color:white;cursor:pointer;table-layout:fixed"></table>
495 + </div>
496 + </div>
497 + <div id="dialog" style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:90px;width:300px;display:none">
498 + <div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
499 + <div id="id_dialogclose" style="float:right;padding:5px;cursor:pointer" onclick="setDialogMode()"><b>X</b></div>
500 + <div id="id_dialogtitle" style="padding:5px"></div>
501 + <div style="width:100%;margin:6px"></div>
502 + </div>
503 + <div style="margin-right:16px;margin-left:8px">
504 + <div id="dialog1" style="margin:auto;text-align:center;margin:3px">
505 + <div id="id_dialogMessage" style="padding:10px"></div>
506 + </div>
507 + <div id="dialog2" style="margin:auto;margin:3px">
508 + <div id="id_dialogOptions"></div>
509 + </div>
510 + <div id="dialog3" style="margin:auto;margin:3px">
511 + <select id="deskkeys" style="width:100%">
512 + <option value="10">Ctrl+Alt+Del</option>
513 + <option value="11">Tab</option>
514 + <option value="5">Win</option>
515 + <option value="0">Win+Down</option>
516 + <option value="1">Win+Up</option>
517 + <option value="2">Win+L</option>
518 + <option value="3">Win+M</option>
519 + <option value="4">Shift+Win+M</option>
520 + <option value="6">Win+R</option>
521 + <option value="7">Alt-F4</option>
522 + <option value="8">Ctrl-W</option>
523 + <option value="9">Alt-Tab</option>
524 + </select>
525 + </div>
526 + <div id="dialog7" style="margin:auto;margin:3px">
527 + <div id="d7meshkvm">
528 + <h4 style="width:100%;border-bottom:1px solid gray">Agent Remote Desktop</h4>
529 + <div style="margin:3px 0 3px 0">
530 + <select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl"></select>
531 + <div style="height:20px">Quality</div>
532 + </div>
533 + <div style="margin:3px 0 3px 0">
534 + <select id="d7bitmapscaling" style="float:right;width:200px;height:20px" dir="rtl">
535 + <option selected="selected" value="1024">100%</option>
536 + <option value="896">87.5%</option>
537 + <option value="768">75%</option>
538 + <option value="640">62.5%</option>
539 + <option value="512">50%</option>
540 + <option value="384">37.5%</option>
541 + <option value="256">25%</option>
542 + <option value="128">12.5%</option>
543 + </select>
544 + <div style="height:20px">Scaling</div>
545 + </div>
546 + <div style="margin:3px 0 3px 0">
547 + <select id="d7framelimiter" style="float:right;width:200px;height:20px" dir="rtl">
548 + <option selected="selected" value="50">Fast</option>
549 + <option value="100">Medium</option>
550 + <option value="400">Slow</option>
551 + <option value="1000">Very slow</option>
552 + </select>
553 + <div style="height:20px">Rate</div>
554 + </div>
555 + </div>
556 + <div id="d7amtkvm">
557 + <h4 style="width:100%;border-bottom:1px solid gray">Intel® AMT Hardware KVM</h4>
558 + <div style="height:26px">
559 + <select id="d7desktopmode" style="float:right;width:200px">
560 + <option value="1">RLE8, Fastest</option>
561 + <option value="2">RLE16, Recommended</option>
562 + <option value="3">RAW8, Slow</option>
563 + <option value="4">RAW16, Very Slow</option>
564 + </select>
565 + <div>Encoding</div>
566 + </div>
567 + <div style="height:60px">
568 + <div style="float:right;border:1px solid #666;width:200px;height:60px;overflow-y:scroll;background-color:white">
569 + <label><input type="checkbox" id="d7showfocus">Show Focus Tool<br></label>
570 + <label><input type="checkbox" id="d7showcursor">Show Local Mouse Cursor<br< label="">&gt;
571 + </br<></label></div>
572 + <div>Other</div>
573 + </div>
574 + </div>
575 + </div>
576 + </div>
577 + <div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:20px">
578 + <input id="idx_dlgCancelButton" type="button" value="Annuler" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">
579 + <input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)">
580 + </div>
581 + </div>
582 + <div id="topMenu" style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:0px 0px 5px 5px;position:fixed;top:50px;right:5px;width:170px;display:none">
583 + <div style="padding:12px;border-top:1px solid gray;color:black;cursor:pointer" onclick="topMenu(2)">My Files</div>
584 + <div style="padding:12px;border-top:1px solid gray;color:black;cursor:pointer" onclick="topMenu(1)">My Account</div>
585 + <div id="logoutMenuOption"><a href="/logout"><div style="padding:12px;border-top:1px solid gray;color:black;cursor:pointer">Logout</div></a></div>
586 + </div>
587 + <iframe name="fileUploadFrame" style="display:none"></iframe>
588 + <script>
589 + 'use strict';
590 +
591 + // Process server-side web state
592 + var webState = '{{{webstate}}}';
593 + if (webState != '') { webState = JSON.parse(decodeURIComponent(webState)); }
594 + for (var i in webState) { localStorage.setItem(i, webState[i]); }
595 + if (!webState.loctag) { delete localStorage.removeItem('loctag'); }
596 +
597 + var args = parseUriArgs();
598 + var debugLevel = parseInt('{{{debuglevel}}}');
599 + var features = parseInt('{{{features}}}');
600 + var sessionTime = parseInt('{{{sessiontime}}}');
601 + var domain = '{{{domain}}}';
602 + var domainUrl = '{{{domainurl}}}';
603 + var authCookie = '{{{authCookie}}}';
604 + var authRelayCookie = '{{{authRelayCookie}}}';
605 + var authCookieRenewTimer = null;
606 + var meshserver = null;
607 + var xdr = null;
608 + var serverinfo = null;
609 + var nodes = [];
610 + var meshes = {};
611 + var filetree = {};
612 + var userinfo = null;
613 + var serverinfo = null;
614 + var users = null;
615 + var nodeShortIdent = 0;
616 + var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
617 + var debugmode = false;
618 + var attemptWebRTC = ((features & 128) != 0);
619 + var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected", "Intel&reg; AMT Connected"];
620 + var files;
621 + var passRequirements = '{{{passRequirements}}}';
622 + if (passRequirements != '') { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
623 + var sessionActivity = Date.now();
624 +
625 + function startup() {
626 + if ((features & 32) == 0) {
627 + // Guard against other site's top frames (web bugs).
628 + var loc = null;
629 + try { loc = top.location.toString().toLowerCase(); } catch (e) { }
630 + if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
631 + }
632 +
633 + if (!args.locale) { var x = getstore('loctag', 0); if ((x != null) && (x != '*')) { args.locale = x; } }
634 +
635 + window.onresize = center;
636 + center();
637 + QV('changeEmailId', (features & 0x200000) == 0);
638 + QH('p1message', "Connecting...");
639 + go(1);
640 +
641 + // Connect to the mesh server
642 + meshserver = MeshServerCreateControl(domainUrl, authCookie);
643 + meshserver.onStateChanged = onStateChanged;
644 + meshserver.onMessage = onMessage;
645 + meshserver.Start();
646 +
647 + // Load desktop settings
648 + var t = localStorage.getItem('desktopsettings');
649 + if (t != null) { desktopsettings = JSON.parse(t); }
650 + applyDesktopSettings();
651 + }
652 +
653 + function onStateChanged(server, state, prevState, errorCode) {
654 + if (state == 0) {
655 + // Control web socket disconnected
656 + setDialogMode(0); // Close any dialog boxes if present
657 + go(0); // Go to disconnection panel
658 + if (errorCode == 'noauth') { QH('p0span', "Unable to perform authentication"); return; }
659 + if (prevState == 2) { setTimeout(serverPoll, 5000); } else { QH('p0span', "Unable to connect web socket"); }
660 + // Clean up here
661 + if (authCookieRenewTimer != null) { clearInterval(authCookieRenewTimer); authCookieRenewTimer = null; }
662 + } else if (state == 2) {
663 + // Fetch list of meshes, nodes, files
664 + meshserver.send({ action: 'meshes' });
665 + meshserver.send({ action: 'nodes' });
666 + meshserver.send({ action: 'files' });
667 + if (xxcurrentView < 2) { go(2); }
668 + authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
669 + }
670 + QV('topMenuIcon', state == 2);
671 + }
672 +
673 + // Poll the server, if it responds, refresh the page.
674 + function serverPoll() {
675 + xdr = null;
676 + try { xdr = new XDomainRequest(); } catch (e) { }
677 + if (!xdr) xdr = new XMLHttpRequest();
678 + xdr.open('HEAD', window.location.href);
679 + xdr.timeout = 15000;
680 + xdr.onload = function () { reload(); };
681 + xdr.onerror = xdr.ontimeout = function () { setTimeout(serverPoll, 10000); };
682 + xdr.send();
683 + }
684 +
685 + function updateSelf() {
686 + QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
687 + QV('manageAuthApp', features & 4096);
688 + QV('manageOtp', ((features & 4096) != 0) && ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)));
689 +
690 + // On the mobile app, don't allow group creation (for now).
691 + QV('p3createMeshLink1', false);
692 + QV('p3createMeshLink2', false);
693 +
694 + if (typeof userinfo.passchange == 'number') {
695 + if (userinfo.passchange == -1) { QH('p2nextPasswordUpdateTime', "- Réinitialiser à la prochaine connexion."); }
696 + else if ((passRequirements != null) && (typeof passRequirements.reset == 'number')) {
697 + var seconds = (userinfo.passchange) + (passRequirements.reset * 86400) - Math.floor(Date.now() / 1000);
698 + if (seconds < 0) { QH('p2nextPasswordUpdateTime', "- Réinitialiser à la prochaine connexion."); }
699 + else if (seconds < 3600) { QH('p2nextPasswordUpdateTime', format("- Réinitialisation en {0} minute {1}.", Math.floor(seconds / 60), addLetterS(Math.floor(seconds / 60)))); }
700 + else if (seconds < 86400) { QH('p2nextPasswordUpdateTime', format("- Réinitialisation dans {0} heure {1}.", Math.floor(seconds / 3600), addLetterS(Math.floor(seconds / 3600)))); }
701 + else { QH('p2nextPasswordUpdateTime', format("- Réinitialiser dans le {0} jour {1}."), Math.floor(seconds / 86400), addLetterS(Math.floor(seconds / 86400))); }
702 + }
703 + }
704 + }
705 +
706 + function addLetterS(x) { return (x > 1) ? 's' : ''; }
707 + function setSessionActivity() { sessionActivity = Date.now(); }
708 + function checkIdleSessionTimeout() { var delta = (Date.now() - sessionActivity); if (delta > serverinfo.timeout) { window.location.href = 'logout'; } }
709 +
710 + function onMessage(server, message) {
711 + switch (message.action) {
712 + case 'serverinfo': {
713 + serverinfo = message.serverinfo;
714 + if (serverinfo.timeout) { setInterval(checkIdleSessionTimeout, 10000); checkIdleSessionTimeout(); }
715 + QV('p3AccountActions', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide Account Actions if in single user mode or domain authentication
716 + QV('logoutMenuOption', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide logout if in single user mode or domain authentication
717 + break;
718 + }
719 + case 'authcookie': {
720 + // Got an authentication cookie refresh
721 + authCookie = message.cookie;
722 + authRelayCookie = message.rcookie;
723 + break;
724 + }
725 + case 'userinfo': {
726 + userinfo = message.userinfo;
727 + QH('p3userName', userinfo.name);
728 + //updateSiteAdmin();
729 + updateSelf();
730 + break;
731 + }
732 + case 'users': {
733 + users = {};
734 + for (var m in message.users) { users[message.users[m]._id] = message.users[m]; }
735 + updateUsers();
736 + break;
737 + }
738 + case 'wssessioncount': {
739 + wssessions = message.wssessions;
740 + updateUsers();
741 + break;
742 + }
743 + case 'meshes': {
744 + meshes = {};
745 + for (var m in message.meshes) { meshes[message.meshes[m]._id] = message.meshes[m]; }
746 + updateMeshes();
747 + updateDevices();
748 + break;
749 + }
750 + case 'files': {
751 + filetree = setupBackPointers(message.filetree);
752 + updateFiles();
753 + //d3updatefiles();
754 + break;
755 + }
756 + case 'nodes': {
757 + nodes = [];
758 + for (var m in message.nodes) {
759 + for (var n in message.nodes[m]) {
760 + if (!meshes[m]) { console.log('Invalid mesh (1): ' + m); continue; }
761 + message.nodes[m][n].namel = message.nodes[m][n].name.toLowerCase();
762 + 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; }
763 + message.nodes[m][n].meshnamel = meshes[m].name.toLowerCase();
764 + message.nodes[m][n].meshid = m;
765 + message.nodes[m][n].state = (message.nodes[m][n].state) ? (message.nodes[m][n].state) : 0;
766 + message.nodes[m][n].desc = message.nodes[m][n].desc;
767 + if (!message.nodes[m][n].icon) message.nodes[m][n].icon = 1;
768 + message.nodes[m][n].ident = ++nodeShortIdent;
769 + nodes.push(message.nodes[m][n]);
770 + }
771 + }
772 + //onSortSelectChange();
773 + //onSearchInputChanged();
774 + updateDevices();
775 + //refreshMap(false, true);
776 + if (xxcurrentView == 0) { if ('{{viewmode}}' != '') { go(parseInt('{{viewmode}}')); } else { setDialogMode(0); go(2); } }
777 + if ('{{currentNode}}' != '') { gotoDevice('{{currentNode}}', parseInt('{{viewmode}}')); }
778 + break;
779 + }
780 + case 'powertimeline': {
781 + if (message.nodeid != powerTimelineReq) break;
782 + powerTimelineNode = message.nodeid;
783 + powerTimeline = message.timeline;
784 + powerTimelineUpdate = Date.now() + 300000; // Update every 5 minutes
785 + if (currentNode._id == message.nodeid) { drawDeviceTimeline(); }
786 + break;
787 + }
788 + case 'otpauth-request': {
789 + if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-request')) {
790 + var secret = message.secret;
791 + if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); }
792 + else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '<br/>' + secret.substring(20) }
793 + QH('d2optinfo', "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, use <a href=\"' + message.url + '\" rel=\"noreferrer noopener\" target=_blank> this link</a> or enter the secret below. Then, enter the current 6 digit token to activate 2-Step login." + '<br /><br /><div style=width:100%;text-align:center><tt id=d2optsecret secret=\"' + message.secret + '\" style=font-size:15px>' + secret + '</tt><br /><br />Token: <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></div>');
794 + QV('idx_dlgOkButton', true);
795 + QE('idx_dlgOkButton', false);
796 + Q('d2otpauthinput').focus();
797 + }
798 + break;
799 + }
800 + case 'otpauth-setup': {
801 + if (xxdialogMode) return;
802 + setDialogMode(2, "Authenticator App", 1, null, message.success ? "<b style=color:green>2-step login 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.");
803 + break;
804 + }
805 + case 'otpauth-clear': {
806 + if (xxdialogMode) return;
807 + setDialogMode(2, "Authenticator App", 1, null, message.success ? "<b style=color:green>2-step login activation removed</b>. You can reactivate this feature at any time." : "<b style=color:red>2-step login activation removal failed</b>. Try again.");
808 + break;
809 + }
810 + case 'otpauth-getpasswords': {
811 + if (xxdialogMode) return;
812 + var x = "One time tokens can be used as secondary authentication. Generate a set, print them and keep them in a safe place.";
813 + 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>';
814 + if (message.passwords) {
815 + var j = 0;
816 + for (var i in message.passwords) {
817 + if (++j % 2) { x += '<tr>'; }
818 + var p = '' + message.passwords[i].p;
819 + while (p.length < 8) { p = '0' + p; }
820 + if (message.passwords[i].u === true) { x += '<td>' + p.substring(0, 4) + '&nbsp;' + p.substring(4); } else { x += '<td><strike style=color:#BBB>' + p.substring(0, 4) + '&nbsp;' + p.substring(4); + '</strike>'; }
821 + }
822 + } else {
823 + x += '<tr><td>' + "No Active Tokens";
824 + }
825 + x += '</table></div></div><br />';
826 + x += '<div><input type=button value=\'' + "Close" + '\' onclick=setDialogMode(0) style=float:right></input>';
827 + x += '<input type=button value=\'' + "New Tokens" + '\' onclick=\'account_manageOtp(1);\'></input>';
828 + if (message.passwords != null) { x += '<input type=button value=\'' + "Clear" + '\' onclick=\'account_manageOtp(2);\'></input>'; }
829 + x += '</div><br />';
830 + setDialogMode(2, "Manage Backup Codes", 8, null, x, 'otpauth-manage');
831 + break;
832 + }
833 + case 'event': {
834 + /*
835 + if (!message.event.nolog) {
836 + events.unshift(message.event);
837 + var eventLimit = parseInt(p3limitdropdown.value);
838 + while (events.length > eventLimit) { events.pop(); } // Remove element(s) at the end
839 + events_update();
840 + }
841 + */
842 + if (message.event.noact) break; // Take no action on this event
843 + switch (message.event.action) {
844 + case 'userWebState': {
845 + // New user web state, update the web page as needed
846 + if (localStorage != null) {
847 + var webstate = JSON.parse(message.event.state);
848 + for (var i in webstate) { localStorage.setItem(i, webstate[i]); }
849 +
850 + // Update the web page
851 + if ((webstate.loctag != null) && (webstate.loctag != oldLoctag)) {
852 + if (webstate.loctag != null) { args.locale = webstate.loctag; } else { delete args.locale; }
853 + updateDevices();
854 + updateMeshes();
855 + }
856 + }
857 + break;
858 + }
859 + case 'accountchange': {
860 + // An account was created or changed
861 + if (userinfo.name == message.event.account.name) {
862 + var newsiteadmin = message.event.account.siteadmin ? message.event.account.siteadmin : 0;
863 + var oldsiteadmin = userinfo.siteadmin ? userinfo.siteadmin : 0;
864 + if ((message.event.account.quota != userinfo.quota) || (((userinfo.siteadmin & 8) == 0) && ((message.event.account.siteadmin & 8) != 0))) { meshserver.send({ action: 'files' }); }
865 + userinfo = message.event.account;
866 + if (oldsiteadmin != newsiteadmin) updateSiteAdmin();
867 + updateSelf();
868 + }
869 + break;
870 + }
871 + case 'createmesh': {
872 + // A new mesh was created
873 + if (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.
874 + meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
875 + updateMeshes();
876 + updateDevices();
877 + meshserver.send({ action: 'files' });
878 + }
879 + break;
880 + }
881 + case 'meshchange': {
882 + // Update mesh information
883 + if (meshes[message.event.meshid] == null) {
884 + // This is a new mesh for us
885 + meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
886 + meshserver.send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh).
887 + } else {
888 + // This is an existing mesh
889 + if (meshes[message.event.meshid].name != message.event.name) {
890 + meshes[message.event.meshid].name = message.event.name;
891 + for (var i in nodes) { if (nodes[i].meshid == message.event.meshid) { nodes[i].meshnamel = message.event.name.toLowerCase(); } }
892 + }
893 + meshes[message.event.meshid].desc = message.event.desc;
894 + meshes[message.event.meshid].links = message.event.links;
895 +
896 + // Check if we lost rights to this mesh in this change.
897 + if (meshes[message.event.meshid].links[userinfo._id] == null) {
898 + if ((xxcurrentView == 20) && (currentMesh == meshes[message.event.meshid])) go(2);
899 + delete meshes[message.event.meshid];
900 +
901 + // Delete all nodes in that mesh
902 + var newnodes = [];
903 + for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } }
904 + nodes = newnodes;
905 +
906 + // If we are looking at a node in the deleted mesh, move back to "My Devices"
907 + if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(2); }
908 + }
909 + }
910 + updateMeshes();
911 + updateDevices();
912 + meshserver.send({ action: 'files' });
913 +
914 + // If we are looking at a mesh that is now deleted, move back to "My Account"
915 + if (xxcurrentView == 20 && currentMesh._id == message.event.meshid) { p20updateMesh(); }
916 + break;
917 + }
918 + case 'deletemesh': {
919 + // Delete the mesh
920 + if (meshes[message.event.meshid]) {
921 + delete meshes[message.event.meshid];
922 + updateMeshes();
923 + meshserver.send({ action: 'files' });
924 + }
925 +
926 + // Delete all nodes in that mesh
927 + var newnodes = [];
928 + for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } }
929 + nodes = newnodes;
930 + updateDevices();
931 +
932 + // If we are looking at a mesh that is now deleted, move back to "My Account"
933 + if (xxcurrentView >= 20 && xxcurrentView < 30 && currentMesh._id == message.event.meshid) { setDialogMode(0); go(2); }
934 + // If we are looking at a node in the deleted mesh, move back to "My Devices"
935 + if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(2); }
936 +
937 + break;
938 + }
939 + case 'addnode': {
940 + var node = message.event.node;
941 + 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.
942 + if (getNodeFromId(node._id) != null) break; // This node is already known.
943 + node.namel = node.name.toLowerCase();
944 + if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
945 + node.meshnamel = meshes[node.meshid].name.toLowerCase();
946 + node.state = 0;
947 + if (!node.icon) node.icon = 1;
948 + node.ident = ++nodeShortIdent;
949 + nodes.push(node);
950 + //onSortSelectChange();
951 + //onSearchInputChanged();
952 + updateDevices();
953 + //updateMapMarkers();
954 + break;
955 + }
956 + case 'removenode': {
957 + var index = -1;
958 + for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
959 + if (index != -1) {
960 + var node = nodes[index];
961 + if (currentNode == node) {
962 + if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(2); }
963 + currentNode = null;
964 + // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
965 + }
966 + nodes.splice(index, 1);
967 + updateDevices();
968 + //updateMapMarkers();
969 + }
970 + break;
971 + }
972 + case 'changenode': {
973 + var index = -1;
974 + for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
975 + if (index != -1) {
976 + var node = nodes[index];
977 +
978 + // Change the node
979 + node.name = message.event.node.name;
980 + node.rname = message.event.node.rname;
981 + node.host = message.event.node.host;
982 + node.desc = message.event.node.desc;
983 + node.publicip = message.event.node.publicip;
984 + node.iploc = message.event.node.iploc;
985 + node.wifiloc = message.event.node.wifiloc;
986 + node.gpsloc = message.event.node.gpsloc;
987 + node.tags = message.event.node.tags;
988 + node.userloc = message.event.node.userloc;
989 + if (message.event.node.agent != null) {
990 + if (node.agent == null) node.agent = {};
991 + if (message.event.node.agent.ver != null) { node.agent.ver = message.event.node.agent.ver; }
992 + if (message.event.node.agent.id != null) { node.agent.id = message.event.node.agent.id; }
993 + if (message.event.node.agent.caps != null) { node.agent.caps = message.event.node.agent.caps; }
994 + if (message.event.node.agent.core != null) { node.agent.core = message.event.node.agent.core; } else { if (node.agent.core) { delete node.agent.core; } }
995 + node.agent.tag = message.event.node.agent.tag;
996 + }
997 + if (message.event.node.intelamt != null) {
998 + if (node.intelamt == null) node.intelamt = {};
999 + if (message.event.node.intelamt.state != null) { node.intelamt.state = message.event.node.intelamt.state; }
1000 + if (message.event.node.intelamt.host != null) { node.intelamt.user = message.event.node.intelamt.host; }
1001 + if (message.event.node.intelamt.user != null) { node.intelamt.user = message.event.node.intelamt.user; }
1002 + if (message.event.node.intelamt.tls != null) { node.intelamt.tls = message.event.node.intelamt.tls; }
1003 + if (message.event.node.intelamt.ver != null) { node.intelamt.ver = message.event.node.intelamt.ver; }
1004 + if (message.event.node.intelamt.tag != null) { node.intelamt.tag = message.event.node.intelamt.tag; }
1005 + if (message.event.node.intelamt.uuid != null) { node.intelamt.uuid = message.event.node.intelamt.uuid; }
1006 + if (message.event.node.intelamt.realm != null) { node.intelamt.realm = message.event.node.intelamt.realm; }
1007 + }
1008 + node.namel = node.name.toLowerCase();
1009 + if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
1010 + if (message.event.node.icon) { node.icon = message.event.node.icon; }
1011 +
1012 + //onSortSelectChange(true);
1013 + //drawNotifications();
1014 + refreshDevice(node._id);
1015 + //updateMapMarkers();
1016 + updateDevices();
1017 +
1018 + //if ((currentNode == node) && (xxdialogMode != null) && (xxdialogTag == '@xxmap')) { p10showNodeLocationDialog(); }
1019 + }
1020 + break;
1021 + }
1022 + case 'nodemeshchange': {
1023 + var index = -1;
1024 + for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
1025 + if (index != -1) {
1026 + var node = nodes[index];
1027 + if (meshes[message.event.newMeshId] == null) {
1028 + // We don't see the new mesh, remove this device
1029 +
1030 + // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
1031 + if (currentNode == node) { if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(2); } currentNode = null; }
1032 + nodes.splice(index, 1);
1033 + } else {
1034 + // We see the new mesh, move this device
1035 + node.meshid = message.event.newMeshId;
1036 + node.meshnamel = meshes[message.event.newMeshId].name.toLowerCase();
1037 + }
1038 + updateDevices();
1039 + refreshDevice(message.event.nodeid);
1040 + } else {
1041 + // This is a new device, add it.
1042 + var node = message.event.node;
1043 + 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.
1044 + node.namel = node.name.toLowerCase();
1045 + if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
1046 + node.meshnamel = meshes[node.meshid].name.toLowerCase();
1047 + node.state = 0;
1048 + if (!node.icon) node.icon = 1;
1049 + node.ident = ++nodeShortIdent;
1050 + if (nodes == null) { }
1051 + nodes.push(node);
1052 +
1053 + // Web page update
1054 + //masterUpdate(1 | 2 | 4 | 16);
1055 + updateDevices();
1056 + }
1057 + break;
1058 + }
1059 + case 'nodeconnect': {
1060 + // Indicated a node has changed connectivity state
1061 + var index = -1;
1062 + for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
1063 + if (index != -1) {
1064 + var node = nodes[index];
1065 +
1066 + // Change the node connection state
1067 + node.conn = message.event.conn;
1068 + node.pwr = message.event.pwr;
1069 + updateDevices();
1070 + //updateMapMarkers();
1071 + //refreshDevice(node._id);
1072 + }
1073 + break;
1074 + }
1075 + case 'login': {
1076 + // Update the last login time
1077 + if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) { users['user/' + domain + '/' + message.event.username.toLowerCase()].login = message.event.time; }
1078 + break;
1079 + }
1080 + case 'notify': {
1081 + //var n = { text: message.event.value };
1082 + //if (message.event.tag != null) { n.tag = message.event.tag; }
1083 + //addNotification(n);
1084 + break;
1085 + }
1086 + case 'stopped': { // Server is stopping.
1087 + // TODO: Disconnect
1088 + break;
1089 + }
1090 + default:
1091 + //console.log('Unknown message.event.action', message.event.action);
1092 + break;
1093 + }
1094 + break;
1095 + }
1096 + default:
1097 + //console.log('Unknown message.action', message.action);
1098 + break;
1099 + }
1100 + }
1101 +
1102 + //
1103 + // Menu System
1104 + //
1105 +
1106 + function topMenu(select) {
1107 + if ((xxdialogMode != null) && (xxdialogMode != 0) && (xxdialogMode != 999)) return;
1108 + if (select === undefined) {
1109 + var x = (QS('topMenu').display == 'none');
1110 + if (x == true) { if ((xxdialogMode == 0) || (xxdialogMode == null)) { QV('topMenu', true); xxdialogMode = 999; } } else { QV('topMenu', false); xxdialogMode = 0; }
1111 + } else {
1112 + QV('topMenu', false);
1113 + xxdialogMode = 0;
1114 + if ((select == 1) && (xxcurrentView != 3)) { goForward('account'); } // My Account
1115 + if ((select == 2) && (xxcurrentView != 5)) { goForward('files'); } // My Files
1116 + }
1117 + }
1118 +
1119 + var backStack = [];
1120 + function goBack() { if (xxdialogMode) return; if (backStack.length > 0) { backStack.pop(); } goStack(); }
1121 + function goForward(id) { if (xxdialogMode) return; backStack.push(id); goStack(); }
1122 + function goStack() {
1123 + if (backStack.length == 0) { go(2); return; }
1124 + var id = backStack[backStack.length - 1], idtype = id.split('/')[0];
1125 + if (idtype == 'node') { setupDeviceMenu(0); gotoDevice(id); }
1126 + if (idtype == 'mesh') { gotoMesh(id); }
1127 + if (idtype == 'account') { go(3); }
1128 + if (idtype == 'devices') { go(2); }
1129 + if (idtype == 'files') { go(5); }
1130 + }
1131 +
1132 + function updateFooterMenu(options) {
1133 + while (options != null && options.length < 3) { options.push({ n: '' }); }
1134 + var x = '', prev = '';
1135 + if (options != null) { for (var i in options) { x += '<td style="cursor:pointer' + ((prev == '') ? '' : ';border-left:solid 1px white') + '" onclick="' + options[i].f + '">' + options[i].n; prev = options[i].n; } }
1136 + QH('footerMenu', '<tr>' + x);
1137 + }
1138 +
1139 + //
1140 + // MY ACCOUNT
1141 + //
1142 +
1143 + function account_manageAuthApp() {
1144 + if (xxdialogMode || ((features & 4096) == 0)) return;
1145 + if (userinfo.otpsecret == 1) { account_removeOtp(); } else { account_addOtp(); }
1146 + }
1147 +
1148 + function account_addOtp() {
1149 + if (xxdialogMode || (userinfo.otpsecret == 1) || ((features & 4096) == 0)) return;
1150 + setDialogMode(2, "Authenticator App", 2, function () { meshserver.send({ action: 'otpauth-setup', secret: Q('d2optsecret').attributes.secret.value, token: Q('d2otpauthinput').value }); }, '<div id=d2optinfo>' + "Loading..." + '</div>', 'otpauth-request');
1151 + meshserver.send({ action: 'otpauth-request' });
1152 + }
1153 +
1154 + function account_addOtpCheck(e) {
1155 + var tokenIsValid = (Q('d2otpauthinput').value.length == 6);
1156 + QE('idx_dlgOkButton', tokenIsValid);
1157 + if (e && (e.keyCode == 13) && tokenIsValid) { dialogclose(1); }
1158 + }
1159 +
1160 + function account_removeOtp() {
1161 + if (xxdialogMode || (userinfo.otpsecret != 1) || ((features & 4096) == 0)) return;
1162 + setDialogMode(2, "Authenticator App", 3, function () { meshserver.send({ action: 'otpauth-clear' }); }, "Confirm removal of authenticator application 2-step login?");
1163 + }
1164 +
1165 + function account_manageOtp(action) {
1166 + if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-manage')) { dialogclose(0); }
1167 + if (xxdialogMode || (userinfo.otpsecret != 1) || ((features & 4096) == 0)) return;
1168 + meshserver.send({ action: 'otpauth-getpasswords', subaction: action });
1169 + }
1170 +
1171 + function account_showVerifyEmail() {
1172 + if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return;
1173 + var x = "Click ok to send a verification mail to:" + '<br /><div style=padding:8px><b>' + EscapeHtml(userinfo.email) + '</b></div>' + "Please wait a few minute to receive the verification.";
1174 + setDialogMode(2, "Email Verification", 3, account_showVerifyEmailEx, x);
1175 + }
1176 +
1177 + function account_showVerifyEmailEx() {
1178 + meshserver.send({ action: 'verifyemail', email: userinfo.email });
1179 + }
1180 +
1181 + function account_showChangeEmail() {
1182 + if (xxdialogMode) return;
1183 + var x = addHtmlValue("Email", '<input id=dp3email style=width:170px maxlength=256 onchange=account_validateEmail() onkeyup=account_validateEmail(event) />');
1184 + setDialogMode(2, "Email Address Change", 3, account_changeEmail, x);
1185 + if (userinfo.email != null) { Q('dp3email').value = userinfo.email; }
1186 + account_validateEmail();
1187 + Q('dp3email').focus();
1188 + }
1189 +
1190 + function account_validateEmail(e, email) {
1191 + QE('idx_dlgOkButton', validateEmail(Q('dp3email').value) && (Q('dp3email').value != userinfo.email));
1192 + if ((e != null) && (e.keyCode == 13)) { dialogclose(1); }
1193 + }
1194 +
1195 + function account_changeEmail() {
1196 + meshserver.send({ action: 'changeemail', email: Q('dp3email').value });
1197 + }
1198 +
1199 + function account_showDeleteAccount() {
1200 + if (xxdialogMode) return;
1201 + var x = '<form method=post><table style=margin-left:10px><input type=hidden name=action value=deleteaccount /><input type=hidden name=authcookie value=' + authCookie + ' /><tr>';
1202 + x += '<td align=right>' + "Password:" + '</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateDeleteAccount() onkeyup=account_validateDeleteAccount() /></td>';
1203 + x += '</tr><tr><td align=right>' + "Password:" + '</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateDeleteAccount() onkeyup=account_validateDeleteAccount() /></td>';
1204 + x += '</tr></table><div style=padding:10px;margin-bottom:4px>';
1205 + x += '<input id=account_dlgCancelButton type=button value=\"' + "Annuler" + '\" style=float:right;width:80px;margin-left:5px onclick=dialogclose(0)>';
1206 + x += '<input id=account_dlgOkButton type=submit value=\"' + "OK" + '\" style="float:right;width:80px" onclick=dialogclose(1)>';
1207 + x += '</div><br /></form>';
1208 + setDialogMode(2, "Delete Account", 0, null, x);
1209 + account_validateDeleteAccount();
1210 + Q('apassword1').focus();
1211 + }
1212 +
1213 +
1214 + function account_showChangePassword() {
1215 + if (xxdialogMode) return false;
1216 + var x = '<table style=margin-left:10px>';
1217 + x += '<tr><td align=right>' + nobreak("Old password:") + '</td><td><input id=apassword0 type=password name=apassword0 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b></b></td></tr>';
1218 + x += '<tr><td align=right>' + nobreak("New password:") + '</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td></tr>';
1219 + x += '<tr><td align=right>' + nobreak("New password:") + '</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>';
1220 + if (features & 0x00010000) { x += '<tr><td align=right>' + "Password hint:" + '</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() onkeydown=account_validateNewPassword() /></td></tr>'; }
1221 + x += '</table>'
1222 + if (passRequirements) {
1223 + var r = [], rc = 0;
1224 + for (var i in passRequirements) { if ((i != 'reset') && (i != 'hint')) { r.push(i + ':' + passRequirements[i]); rc++; } }
1225 + if (rc > 0) { x += '<br /><span style=font-size:x-small>' + format("Requirements: {0}.", r.join(', ')) + '</span>'; }
1226 + }
1227 + x += '<br />';
1228 + setDialogMode(2, "Change Password", 3, account_showChangePasswordEx, x);
1229 + Q('apassword0').focus();
1230 + account_validateNewPassword();
1231 + return false;
1232 + }
1233 +
1234 + function account_showChangePasswordEx() {
1235 + if (Q('apassword1').value == Q('apassword2').value) {
1236 + var r = { action: 'changepassword', oldpass: Q('apassword0').value, newpass: Q('apassword1').value };
1237 + if (features & 0x00010000) { r.hint = Q('apasswordhint').value; }
1238 + meshserver.send(r);
1239 + }
1240 + }
1241 +
1242 + function account_createMesh() {
1243 + if (xxdialogMode) return;
1244 +
1245 + // Check if we are disallowed from creating a device group
1246 + if ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 64) != 0)) { setDialogMode(2, "New Device Group", 1, null, "This account does not have the rights to create a new device group."); return; }
1247 +
1248 + // Remind the user to verify the email address
1249 + 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\" to change and verify an email address."); return; }
1250 +
1251 + // Remind the user to add two factor authentication
1252 + 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\" and look at the \"Account Security\" section."); return; }
1253 +
1254 + // We are allowed, let's prompt to information
1255 + var x = addHtmlValue("Name", '<input id=dp3meshname style=width:170px maxlength=64 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate() />');
1256 + x += addHtmlValue("Type", '<div style=width:170px;margin:0;padding:0><select id=dp3meshtype style=width:100% onchange=account_validateMeshCreate() ><option value=2>' + "Software Agent Group" + '</option><option value=1>' + "Intel&reg; AMT only" + '</option></select></div>');
1257 + x += addHtmlValue("Description", '<div style=width:170px;margin:0;padding:0><textarea id=dp3meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
1258 + setDialogMode(2, "Create Device Group", 3, account_createMeshEx, x);
1259 + account_validateMeshCreate();
1260 + Q('dp3meshname').focus();
1261 + }
1262 +
1263 + function account_validateMeshCreate() {
1264 + QE('idx_dlgOkButton', Q('dp3meshname').value.length > 0);
1265 + }
1266 +
1267 + function account_createMeshEx(button, tag) {
1268 + meshserver.send({ action: 'createmesh', meshname: Q('dp3meshname').value, meshtype: Q('dp3meshtype').value, desc: Q('dp3meshdesc').value });
1269 + }
1270 +
1271 + function account_validateDeleteAccount() {
1272 + QE('account_dlgOkButton', (Q('apassword1').value.length > 0) && (Q('apassword1').value == Q('apassword2').value));
1273 + }
1274 +
1275 + function account_validateNewPassword() {
1276 + var r = '', ok = (Q('apassword0').value.length > 0) && (Q('apassword1').value.length > 0) && (Q('apassword1').value == Q('apassword2').value) && (Q('apassword0').value != Q('apassword1').value);
1277 + if ((features & 0x00010000) && (Q('apasswordhint').value == Q('apassword1').value)) { ok = false; }
1278 + if (Q('apassword1').value != '') {
1279 + if (passRequirements == null || passRequirements == '') {
1280 + // No password requirements, display password strength
1281 + var passStrength = checkPasswordStrength(Q('apassword1').value);
1282 + if (passStrength >= 80) { r = '<span style=color:green>Strong<span>'; } else if (passStrength >= 60) { r = '<span style=color:blue>&#9679;<span>'; } else { r = '<span style=color:red>&#9679;<span>'; }
1283 + } else {
1284 + // Password requirements provided, use that
1285 + var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
1286 + if (passReq == false) { ok = false; r = '<span style=color:red>' + "Policy" + '<span>' }
1287 + }
1288 + }
1289 + QH('dxPassWarn', r);
1290 + //QE('account_dlgOkButton', ok);
1291 + QE('idx_dlgOkButton', ok);
1292 + }
1293 +
1294 + // Return a password strength score
1295 + function checkPasswordStrength(password) {
1296 + var r = 0, letters = {}, varCount = 0, variations = { digits: /\d/.test(password), lower: /[a-z]/.test(password), upper: /[A-Z]/.test(password), nonWords: /\W/.test(password) }
1297 + if (!password) return 0;
1298 + for (var i = 0; i < password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; }
1299 + for (var c in variations) { varCount += (variations[c] == true) ? 1 : 0; }
1300 + return parseInt(r + (varCount - 1) * 10);
1301 + }
1302 +
1303 + // Check password requirements
1304 + function checkPasswordRequirements(password, requirements) {
1305 + if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
1306 + if (requirements.min) { if (password.length < requirements.min) return false; }
1307 + if (requirements.max) { if (password.length > requirements.max) return false; }
1308 + var num = 0, lower = 0, upper = 0, nonalpha = 0;
1309 + for (var i = 0; i < password.length; i++) {
1310 + if (/\d/.test(password[i])) { num++; }
1311 + if (/[a-z]/.test(password[i])) { lower++; }
1312 + if (/[A-Z]/.test(password[i])) { upper++; }
1313 + if (/\W/.test(password[i])) { nonalpha++; }
1314 + }
1315 + if (requirements.num && (num < requirements.num)) return false;
1316 + if (requirements.lower && (lower < requirements.lower)) return false;
1317 + if (requirements.upper && (upper < requirements.upper)) return false;
1318 + if (requirements.nonalpha && (nonalpha < requirements.nonalpha)) return false;
1319 + return true;
1320 + }
1321 +
1322 + function updateMeshes() {
1323 + var r = '', count = 0;
1324 + for (i in meshes) {
1325 + count++;
1326 +
1327 + // Mesh rights
1328 + var meshrights = meshes[i].links[userinfo._id].rights;
1329 + var rights = "Partial Rights";
1330 + if (meshrights == 0xFFFFFFFF) rights = "Full Administrator"; else if (meshrights == 0) rights = "No Rights";
1331 +
1332 + // Print the mesh information
1333 + r += '<div style=cursor:pointer onclick=goForward(\'' + i + '\')>';
1334 + r += '<div style="float:left;margin-left:4px"><img src="/images/meshicon50.png" width=50 height=50 /></div>';
1335 + r += '<div style="width:auto;height:40px;background-color:lightgray;margin-top:5px;margin-bottom:5px;margin-left:60px;padding-top:5px;padding-bottom:5px;border-radius:8px 0px 0px 8px">';
1336 + r += '<div><div style=padding-left:12px;padding-top:2px><b>' + EscapeHtml(meshes[i].name) + '</b></div><div style=padding-left:12px;padding-top:3px;color:gray>' + rights + '</div></div>';
1337 + r += '</div></div>';
1338 + }
1339 +
1340 + QH('p3meshes', r);
1341 + QV('p3noMeshFound', count == 0);
1342 + }
1343 +
1344 + function gotoMesh(meshid) {
1345 + currentMesh = meshes[meshid];
1346 + if (currentMesh == null) { goBack(); }
1347 + p20updateMesh();
1348 + go(20);
1349 + }
1350 +
1351 + //
1352 + // MY FILES
1353 + //
1354 +
1355 + var filetreelinkpath;
1356 + var filetreelocation = [];
1357 +
1358 + function p5refreshFiles() { meshserver.send({ action: 'files' }); }
1359 +
1360 + function updateFiles() {
1361 + QV('MainMenuMyFiles', ((features & 8) == 0));
1362 + if ((features & 8) != 0) return; // If running on a server without files, exit now.
1363 + var html1 = '', html2 = '', displayPath = '<a style=cursor:pointer onclick=p5folderup(0)>' + "Root" + '</a>', fullPath = 'Root', publicPath, filetreex = filetree, folderdepth = 1;
1364 +
1365 + // Navigate to path location, build the paths at the same time
1366 + var filetreelocation2 = [], oldlinkpath = filetreelinkpath, checkedBoxes = [], checkboxes = document.getElementsByName('fc');
1367 + for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedBoxes.push(checkboxes[i].value) }; } // Save all existing checked boxes
1368 +
1369 + filetreelinkpath = '';
1370 + for (var i in filetreelocation) {
1371 + if ((filetreex.f != null) && (filetreex.f[filetreelocation[i]] != null)) {
1372 + filetreelocation2.push(filetreelocation[i]);
1373 + fullPath += ' / ' + filetreelocation[i];
1374 + if ((folderdepth == 1)) {
1375 + var sp = filetreelocation[i].split('/');
1376 + publicPath = window.location + sp[0] + 'files/' + sp[2];
1377 + //if (filetreelocation[i] === userinfo._id) { filetreelinkpath += 'self'; } else { filetreelinkpath += (sp[0] + '/' + sp[2]); }
1378 + filetreelinkpath += filetreelocation[i];
1379 + } else {
1380 + if (filetreelinkpath != '') { filetreelinkpath += '/' + filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + filetreelocation[i]; } }
1381 + }
1382 + filetreex = filetreex.f[filetreelocation[i]];
1383 + displayPath += ' / <a style=cursor:pointer onclick=p5folderup(' + folderdepth + ')>' + (filetreex.n != null ? filetreex.n : filetreelocation[i]) + '</a>';
1384 + folderdepth++;
1385 + } else {
1386 + break;
1387 + }
1388 + }
1389 + filetreelocation = filetreelocation2; // In case we could not go down the full path, we set the new path location here.
1390 + var publicfolder = fullPath.toLowerCase().startsWith('root / ' + userinfo._id + ' / public');
1391 +
1392 + // Sort the files
1393 + var filetreexx = p5sort_files(filetreex.f);
1394 +
1395 + // Display all files and folders at this location
1396 + for (var i in filetreexx) {
1397 + // Figure out the name and shortname
1398 + var f = filetreexx[i], name = f.n, shortname;
1399 + shortname = name;
1400 + if (name.length > 40) { shortname = EscapeHtml(name.substring(0, 40)) + "..."; } else { shortname = EscapeHtml(name); }
1401 + name = EscapeHtml(name);
1402 +
1403 + // Figure out the date
1404 + //var fdatestr = '';
1405 + //if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + '/' + (fdate.getDate()) + '/' + fdate.getFullYear() + ' ' + printTime(fdate) + '&nbsp;'; }
1406 +
1407 + // Figure out the size
1408 + var fsize = '';
1409 + if (f.s != null) { fsize = getFileSizeStr(f.s); }
1410 +
1411 + var h = '';
1412 + if (f.t < 3 || f.t == 4) {
1413 + var right = (f.t == 1 || f.t == 4) ? p5getQuotabar(f) : '';
1414 + h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + name + '\'>&nbsp;<span style=float:right;padding-right:4px>' + right + '</span><span><div class=fileIcon' + f.t + '></div><a style=cursor:pointer onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")>' + shortname + '</a></span></div>';
1415 + } else {
1416 + var link = shortname;
1417 + var publiclink = '';
1418 + if (publicfolder) { publiclink = ' (<a style=cursor:pointer onclick=\'p5showPublicLink(\"' + publicPath + '/' + f.nx + '\")\'>' + "Link" + '</a>)'; }
1419 + if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" href=\"downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '\">' + shortname + '</a>' + publiclink; }
1420 + h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + f.nx + '\'>&nbsp;<span style=float:right;padding-right:4px>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
1421 + }
1422 +
1423 + if (f.t < 3) { html1 += h; } else { html2 += h; }
1424 + }
1425 +
1426 + //if (f.parent == null) { }
1427 + QH('p5rightOfButtons', p5getQuotabar(filetreex));
1428 +
1429 + QH('p5files', html1 + html2);
1430 + QH('p5currentpath', displayPath);
1431 + QE('p5FolderUp', filetreelocation.length != 0);
1432 + QV('p5PublicShare', publicfolder);
1433 +
1434 + // Re-check all boxes if needed
1435 + if (oldlinkpath == filetreelinkpath) {
1436 + checkboxes = document.getElementsByName('fc');
1437 + for (var i = 0; i < checkboxes.length; i++) {
1438 + checkboxes[i].checked = (checkedBoxes.indexOf(checkboxes[i].value) >= 0);
1439 + }
1440 + }
1441 +
1442 + p5setActions();
1443 + }
1444 +
1445 + function getNiceSize(bytes) {
1446 + if (bytes <= 0) return "Storage exceed";
1447 + if (bytes < 2048) return format("{0}b left", bytes);
1448 + if (bytes < 2097152) return format("{0}k left", Math.round(bytes / 1024));
1449 + if (bytes < 2147483648) return format("{0}m left", Math.round(bytes / 1024 / 1024));
1450 + return format("{0}g left", Math.round(bytes / 1024 / 1024 / 1024));
1451 + }
1452 +
1453 + function p5getQuotabar(f) {
1454 + while (f.t > 1 && f.t != 4) { f = f.parent; }
1455 + if ((f.t != 1 && f.t != 4) || (f.maxbytes == null)) return '';
1456 + return getNiceSize(f.maxbytes - f.s) + ' <progress style=height:10px;width:100px value=' + f.s + ' max=' + f.maxbytes + ' />';
1457 + }
1458 +
1459 + function p5showPublicLink(u) { setDialogMode(2, "Public Link", 1, null, '<input type=text style=width:100% value="' + u + '" readonly />'); }
1460 +
1461 + var sortorder;
1462 + function p5sort_filename(a, b) { if (a.ln > b.ln) return (1 * sortorder); if (a.ln < b.ln) return (-1 * sortorder); return 0; }
1463 + function p5sort_timestamp(a, b) { if (a.d > b.d) return (1 * sortorder); if (a.d < b.d) return (-1 * sortorder); return 0; }
1464 + function p5sort_bysize(a, b) { if (a.s == b.s) return p5sort_filename(a, b); return (((a.s - b.s)) * sortorder); }
1465 +
1466 + function p5sort_files(files) {
1467 + var r = [], sortselection = Q('p5sortdropdown').value;
1468 + for (var i in files) { files[i].nx = i; if (files[i].n == null) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
1469 + sortorder = 1;
1470 + if (sortselection > 3) { sortorder = -1; sortselection -= 3; }
1471 + if (sortselection == 1) { r.sort(p5sort_filename); }
1472 + else if (sortselection == 2) { r.sort(p5sort_bysize); }
1473 + else if (sortselection == 3) { r.sort(p5sort_timestamp); }
1474 + return r;
1475 + }
1476 +
1477 + function p5setActions() {
1478 + var cc = getFileSelCount(), tc = getFileCount(), sfc = getFileSelCount(false); // In order: number of entires selected, number of total entries, number of selected entires that are files (not folders)
1479 + QE('p5DeleteFileButton', (cc > 0) && (filetreelocation.length > 0));
1480 + QE('p5NewFolderButton', filetreelocation.length > 0);
1481 + QE('p5UploadButton', filetreelocation.length > 0);
1482 + QE('p5RenameFileButton', (cc == 1) && (filetreelocation.length > 0));
1483 + QE('p5SelectAllButton', tc > 0);
1484 + Q('p5SelectAllButton').value = (cc > 0 ? "None" : "Tout");
1485 + QE('p5CutButton', (sfc > 0) && (cc == sfc));
1486 + QE('p5CopyButton', (sfc > 0) && (cc == sfc));
1487 + QE('p5PasteButton', (p5clipboard != null) && (p5clipboard.length > 0) && (filetreelocation.length > 0));
1488 + }
1489 +
1490 + function getFileSelCount(includeDirs) { var cc = 0, checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == '3'))) cc++; } return cc; }
1491 + function getFileSelDirCount() { var cc = 0, checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '999')) cc++; } return cc; }
1492 + function getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fc'); return checkboxes.length; }
1493 + function p5selectallfile() { var nv = (getFileSelCount() == 0), checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p5setActions(); }
1494 + function setupBackPointers(x) { if (x.f != null) { var fs = 0, fc = 0; for (var i in x.f) { setupBackPointers(x.f[i]); x.f[i].parent = x; if (x.f[i].s) { fs += x.f[i].s; } if (x.f[i].c) { fc += x.f[i].c; } if (x.f[i].t == 3) { fc++; } } x.s = fs; x.c = fc; } return x; }
1495 + function getFileSizeStr(size) { if (size == 1) return "1 octet"; return format("{0} octets", size); }
1496 + function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); return false; }
1497 + function p5folderset(x) { filetreelocation.push(decodeURIComponent(x)); updateFiles(); return false; }
1498 + function p5createfolder() { setDialogMode(2, "New Folder", 3, p5createfolderEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck(event) style=width:100% />'); focusTextBox('p5renameinput'); p5fileNameCheck(); }
1499 + function p5createfolderEx() { meshserver.send({ action: 'fileoperation', fileop: 'createfolder', path: filetreelocation, newfolder: Q('p5renameinput').value }); }
1500 + function p5deletefile() { var cc = getFileSelCount(), rec = (getFileSelDirCount() > 0) ? '<br /><br /><label><input type=checkbox id=p5recdeleteinput>' + "Recursive delete" + '</label><br>' : '<input type=checkbox id=p5recdeleteinput style=\'display:none\'>'; setDialogMode(2, "Delete", 3, p5deletefileEx, (cc > 1) ? (format("Delete {0} selected items?", cc) + rec) : ("Delete selected item?" + rec)); }
1501 + function p5deletefileEx() { var delfiles = [], checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { delfiles.push(checkboxes[i].value); } } meshserver.send({ action: 'fileoperation', fileop: 'delete', path: filetreelocation, delfiles: delfiles, rec: Q('p5recdeleteinput').checked }); }
1502 + function p5renamefile() { var renamefile, checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { renamefile = checkboxes[i].value; } } setDialogMode(2, "Rename", 3, p5renamefileEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck(event) style=width:100% value="' + renamefile + '" />', { action: 'fileoperation', fileop: 'rename', path: filetreelocation, oldname: renamefile }); focusTextBox('p5renameinput'); p5fileNameCheck(); }
1503 + function p5renamefileEx(b, t) { t.newname = Q('p5renameinput').value; meshserver.send(t); }
1504 + function p5fileNameCheck(e) { var x = isFilenameValid(Q('p5renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e && e.keyCode == 13)) { dialogclose(1); } }
1505 + var isFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); } })();
1506 + function p5uploadFile() { setDialogMode(2, "Upload File", 3, p5uploadFileEx, '<form method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame><input type=text name=link style=display:none id=p5uploadpath value=\"' + encodeURIComponent(filetreelinkpath) + '\" /><input type=file name=files id=p5uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p5uploadinput\')" /><input type=hidden name=authCookie value=' + authCookie + ' /><input type=submit id=p5loginSubmit style=display:none /></form>'); updateUploadDialogOk('p5uploadinput'); }
1507 + function p5uploadFileEx() { Q('p5loginSubmit').click(); }
1508 + function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
1509 +
1510 + var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
1511 + function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); }
1512 + function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Confim {0} of {1} entrie{2} to this location?", (p5clipboardCut == 0 ? 'copy' : 'move'), p5clipboard.length, ((p5clipboard.length > 1) ? 's' : '')) } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
1513 + function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0 ? 'copy' : 'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } }
1514 + function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Holding {0} entrie{1} for {2}", p5clipboard.length, ((p5clipboard.length > 1) ? 's' : ''), (p5clipboardCut == 0 ? "copy" : "move")) + ', <a href=# onclick="return p5clearClip()" style=cursor:pointer>' + "Clear" + '</a>.' } QH('p5bottomstatus', x); p5setActions(); }
1515 + function p5clearClip() { p5clipboard = null; p5clipboardFolder = null; p5clipboardCut = 0; p5updateClipview(); return false; }
1516 +
1517 + function p5fileDragDrop(e) {
1518 + haltEvent(e);
1519 + QV('bigfail', false);
1520 + QV('bigok', false);
1521 + //QV('p5fileCatchAllInput', false);
1522 + if (e.dataTransfer == null || e.dataTransfer.files.length == 0 || filetreelocation.length == 0) return;
1523 + var names = [], sizes = [], types = [], datas = [], readercount = e.dataTransfer.files.length;
1524 + for (var i = 0; i < e.dataTransfer.files.length; i++) {
1525 + var reader = new FileReader(), file = e.dataTransfer.files[i];
1526 + names.push(file.name);
1527 + sizes.push(file.size);
1528 + types.push(file.type);
1529 + reader.onload = function (event) {
1530 + datas.push(event.target.result);
1531 + if (--readercount == 0) {
1532 + Q('p5fileDragName').value = names.join('*');
1533 + Q('p5fileDragSize').value = sizes.join('*');
1534 + Q('p5fileDragType').value = types.join('*');
1535 + Q('p5fileDragData').value = datas.join('*');
1536 + Q('p5fileDragLink').value = encodeURIComponent(filetreelinkpath);
1537 + Q('p5loginSubmit2').click();
1538 + }
1539 + }
1540 + reader.readAsDataURL(file);
1541 + }
1542 + }
1543 +
1544 + var p5dragtimer = null;
1545 + function p5fileDragOver(e) {
1546 + haltEvent(e);
1547 + if (p5dragtimer != null) { clearTimeout(p5dragtimer); p5dragtimer = null; }
1548 + var ac = true; // TODO: Set to true if we can accept the file
1549 + if (filetreelocation.length == 0) { ac = false; }
1550 + QV('bigok', ac);
1551 + QV('bigfail', !ac);
1552 + //QV('p5fileCatchAllInput', ac);
1553 + }
1554 +
1555 + function p5fileDragLeave(e) {
1556 + haltEvent(e);
1557 + if (e.target.id != 'p5filetable') {
1558 + QV('bigfail', false);
1559 + QV('bigok', false);
1560 + //QV('p5fileCatchAllInput', false);
1561 + } else {
1562 + p5dragtimer = setTimeout('QV(\'bigfail\',false);QV(\'bigok\',false);p5dragtimer=null;', 200);
1563 + }
1564 + }
1565 +
1566 + //
1567 + // MY DEVICES
1568 + //
1569 +
1570 + function ondeskkeypress(e) {
1571 + toggleSoftKeys(0);
1572 + Q('DeskSoftInput').value = '';
1573 + setSessionActivity();
1574 + if (desktop && !xxdialogMode && xxcurrentView == 10) {
1575 + // Check what keys we are allows to send
1576 + if (currentNode != null) {
1577 + var mesh = meshes[currentNode.meshid];
1578 + var meshrights = mesh.links[userinfo._id].rights;
1579 + var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
1580 + if (inputAllowed == false) return false;
1581 + var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
1582 + if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
1583 + }
1584 + return desktop.m.handleKeys(e);
1585 + }
1586 + }
1587 +
1588 + function ondeskkeydown(e) {
1589 + toggleSoftKeys(0);
1590 + Q('DeskSoftInput').value = '';
1591 + setSessionActivity();
1592 + if (desktop && !xxdialogMode && xxcurrentView == 10) {
1593 + // Check what keys we are allows to send
1594 + if (currentNode != null) {
1595 + var mesh = meshes[currentNode.meshid];
1596 + var meshrights = mesh.links[userinfo._id].rights;
1597 + var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
1598 + if (inputAllowed == false) return false;
1599 + var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
1600 + if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
1601 + }
1602 + return desktop.m.handleKeyDown(e);
1603 + }
1604 + }
1605 +
1606 + function ondeskkeyup(e) {
1607 + toggleSoftKeys(0);
1608 + Q('DeskSoftInput').value = '';
1609 + setSessionActivity();
1610 + if (desktop && !xxdialogMode && xxcurrentView == 10) {
1611 + // Check what keys we are allows to send
1612 + if (currentNode != null) {
1613 + var mesh = meshes[currentNode.meshid];
1614 + var meshrights = mesh.links[userinfo._id].rights;
1615 + var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
1616 + if (inputAllowed == false) return false;
1617 + var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
1618 + if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
1619 + }
1620 + return desktop.m.handleKeyUp(e);
1621 + }
1622 + }
1623 +
1624 + // Since the update device call can be quite frequent, we can moderate it and only call it at most 5 times a second.
1625 + var updateDevicesTimer = null;
1626 + function updateDevices() { if (updateDevicesTimer != null) return; updateDevicesTimer = setTimeout(updateDevicesEx, 200); }
1627 +
1628 + var sort = 0;
1629 + var deviceHeaderId = 0;
1630 + var deviceHeaderCount;
1631 + var deviceHeaders = {};
1632 + var showRealNames = false;
1633 + var deviceHeaderTotal = 0;
1634 + var deviceHeaders = {};
1635 + var deviceHeadersTitles = {};
1636 + function updateDevicesEx() {
1637 + if (updateDevicesTimer != null) { clearTimeout(updateDevicesTimer); updateDevicesTimer = null; }
1638 + var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, groups = {}, groupCount = {};
1639 +
1640 + // 3 wide, list view or desktop view
1641 + deviceHeaderId = 0;
1642 + deviceHeaderCount = {};
1643 + deviceHeaderTotal = 0;
1644 + deviceHeaders = {};
1645 + deviceHeadersTitles = {};
1646 + var current;
1647 +
1648 + // Perform node sort
1649 + if (sort == 0) { nodes.sort(meshSort); }
1650 + else if (sort == 1) { nodes.sort(powerSort); }
1651 + else if (sort == 2) { if (showRealNames == true) { nodes.sort(deviceHostSort); } else { nodes.sort(deviceSort); } }
1652 +
1653 + // Go thru the list of nodes and display them
1654 + for (var i in nodes) {
1655 + if (nodes[i].v == false) continue;
1656 + var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links[userinfo._id];
1657 + if (meshlinks == null) continue;
1658 + var meshrights = meshlinks.rights;
1659 +
1660 + if (sort == 0) {
1661 + // Mesh header
1662 + nodes.sort(meshSort);
1663 + if (nodes[i].meshid != current) {
1664 + deviceHeaderSet();
1665 + var extra = '';
1666 + if (meshes[nodes[i].meshid].mtype == 1) { extra = '<span style=color:lightgray>' + ", Intel&reg; AMT only" + '</span>'; }
1667 + if (current != null) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
1668 + r += '<div class=DevSt style=padding-top:4px><span style=float:right>';
1669 + //r += getMeshActions(mesh2, meshrights);
1670 + r += '</span><span id=MxMESH style=cursor:pointer onclick=goForward("' + nodes[i].meshid + '")>' + EscapeHtml(meshes[nodes[i].meshid].name) + '</span>' + extra + '<span id=DevxHeader' + deviceHeaderId + ' style=color:lightgray></span></div>';
1671 + current = nodes[i].meshid;
1672 + displayedMeshes[current] = 1;
1673 + c = 0;
1674 + }
1675 + } else if (sort == 1) {
1676 + // Power header
1677 + if (nodes[i].pwr !== current) {
1678 + deviceHeaderSet();
1679 + if (current !== null) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
1680 + r += '<div class=DevSt style=width:100%;padding-top:4px><span>' + PowerStateStr2(nodes[i].pwr) + '</span><span id=DevxHeader' + deviceHeaderId + ' style=color:lightgray></span></div>';
1681 + current = nodes[i].pwr;
1682 + c = 0;
1683 + }
1684 + } else if (sort == 2) {
1685 + // Device header
1686 + if (current == null) { current = '1'; }
1687 + }
1688 +
1689 + count++;
1690 + var title = EscapeHtml(nodes[i].name);
1691 + if (title.length == 0) { title = '<i>' + "None" + '</i>'; }
1692 + if ((nodes[i].rname != null) && (nodes[i].rname.length > 0)) { title += " / " + EscapeHtml(nodes[i].rname); }
1693 + var name = EscapeHtml(nodes[i].name);
1694 + if (showRealNames == true && nodes[i].rname != null) name = EscapeHtml(nodes[i].rname);
1695 + if (name.length == 0) { name = '<i>' + "None" + '</i>'; }
1696 +
1697 + // Node
1698 + var icon = nodes[i].icon, nodestate = NodeStateStr(nodes[i]);
1699 + if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; }
1700 + r += '<div style=cursor:pointer onclick=goForward(\'' + nodes[i]._id + '\')>';
1701 + r += '<div class="i' + icon + '" style="float:left;margin-left:4px"></div>';
1702 + r += '<div style="width:auto;height:40px;background-color:lightgray;margin-top:5px;margin-bottom:5px;margin-left:60px;padding-top:5px;padding-bottom:5px;border-radius:8px 0px 0px 8px">';
1703 + r += '<div><div style=padding-left:12px;padding-top:2px><b>' + name + '</b></div><div style=padding-left:12px;padding-top:3px;color:gray>' + nodestate + '</div></div>';
1704 + r += '</div></div>';
1705 +
1706 + // If we are displaying devices by group, put the device in the right group.
1707 + /*
1708 + if ((sort == 3) && (r != '')) {
1709 + if (nodes[i].tags) {
1710 + for (var j in nodes[i].tags) {
1711 + var tag = nodes[i].tags[j];
1712 + if (groups[tag] == null) { groups[tag] = r; groupCount[tag] = 1; } else { groups[tag] += r; groupCount[tag] += 1; }
1713 + if (view == 3) break;
1714 + }
1715 + }
1716 + r = '';
1717 + }
1718 + */
1719 +
1720 + deviceHeaderTotal++;
1721 + if (typeof deviceHeaderCount[nodes[i].state] == 'undefined') { deviceHeaderCount[nodes[i].state] = 1; } else { deviceHeaderCount[nodes[i].state]++; }
1722 + }
1723 +
1724 + // Display all empty meshes, we need to do this because users can add devices to these at any time.
1725 + if (sort == 0) {
1726 + for (var i in meshes) {
1727 + var mesh = meshes[i], meshlink = mesh.links[userinfo._id];
1728 + if (meshlink != null) {
1729 + var meshrights = meshlink.rights;
1730 + if (displayedMeshes[mesh._id] == null) {
1731 + if ((current != '') && (r != '')) { r += '</tr></table>'; }
1732 + r += '<div><div colspan=3 class=DevSt><span style=float:right>';
1733 + //r += getMeshActions(mesh, meshrights);
1734 + r += '</span><span id=MxMESH style=cursor:pointer onclick=goForward("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></div>';
1735 + if (mesh.mtype == 1) { r += '<div style=padding:10px><i>' + "No Intel&reg; AMT devices in this group"; }
1736 + if (mesh.mtype == 2) { r += '<div style=padding:10px><i>' + "No devices in this group"; }
1737 + r += '.</i></div></div>';
1738 + current = mesh._id;
1739 + count++;
1740 + }
1741 + }
1742 + }
1743 + }
1744 +
1745 + if (count == 0) {
1746 + QH('xdevices', '<div style="margin-top:50px;text-align:center"><span style="font-size:30px">' + "No devices" + '</span><br /><br />' + "Use the desktop version of this website to add devices." + '</div>');
1747 + } else {
1748 + QH('xdevices', r);
1749 + }
1750 + deviceHeaderSet();
1751 + for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
1752 + for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
1753 + }
1754 +
1755 + var powerStatetable = ['', "Powered", "Sleep", "Sleep", "Sleep", "Hibernating", "Power off", "Present"];
1756 + var powerStateStrings = ['', "Powered", "Sleeping", "Sleeping", "Deep Sleep", "Hibernating", "Soft-Off", "Present"];
1757 + 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"];
1758 + var powerColorTable = ['#00000000', 'black', 'blue', 'blue', 'lightblue', 'blueviolet', 'darkgreen', 'lightseagreen', 'lightseagreen'];
1759 + function NodeStateStr(node) {
1760 + var states = [];
1761 + if (node.state > 0 && node.state < powerStatetable.length) state.push(powerStatetable[node.state]);
1762 + if (node.conn) {
1763 + if ((node.conn & 1) != 0) { states.push('<span>' + "Agent" + '</span>'); }
1764 + if ((node.conn & 2) != 0) { states.push('<span>' + "CIRA" + '</span>'); }
1765 + else if ((node.conn & 4) != 0) { states.push('<span>' + "Intel&reg; AMT" + '</span>'); }
1766 + if ((node.conn & 8) != 0) { states.push('<span>' + "Relay" + '</span>'); }
1767 + if ((node.conn & 16) != 0) { states.push('<span>' + "MQTT" + '</span>'); }
1768 + }
1769 + if ((node.pwr != null) && (node.pwr != 0)) { states.push(powerStateStrings[node.pwr]); }
1770 + return states.join(', ');
1771 + }
1772 +
1773 + function PowerStateStr(x) {
1774 + if (x < powerStatetable.length) return powerStatetable[x];
1775 + return '';
1776 + }
1777 +
1778 + function PowerStateStr2(x) {
1779 + if ((x != 0) && (x < powerStatetable.length)) return powerStatetable[x];
1780 + return "Inconnue";
1781 + }
1782 +
1783 + function onSortSelectChange(skipsave) {
1784 + sort = document.getElementById('sortselect').selectedIndex;
1785 + if (!skipsave) { putstore('sort', sort); }
1786 + updateDevicesEx();
1787 + }
1788 +
1789 + function deviceHeaderSet() {
1790 + if (deviceHeaderId == 0) { deviceHeaderId = 1; return; }
1791 + deviceHeaders['DevxHeader' + deviceHeaderId] = ', ' + deviceHeaderTotal + ((deviceHeaderTotal == 1) ? "nœud" : "noeuds");
1792 + var title = '';
1793 + for (var x in deviceHeaderCount) { if (title.length > 0) title += ', '; title += deviceHeaderCount[x] + ' ' + PowerStateStr2(x); }
1794 + deviceHeadersTitles['DevxHeader' + deviceHeaderId] = title;
1795 + deviceHeaderId++;
1796 + deviceHeaderCount = {};
1797 + deviceHeaderTotal = 0;
1798 + }
1799 +
1800 + 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; }
1801 + function powerSort(a, b) { var ap = a.pwr ? a.pwr : 0; var bp = b.pwr ? b.pwr : 0; 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; } } if (ap > bp) return 1; if (ap < bp) return -1; return 0; }
1802 + function deviceSort(a, b) { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; }
1803 + function deviceHostSort(a, b) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; }
1804 +
1805 + //
1806 + // MY DEVICE
1807 + //
1808 +
1809 + function refreshDevice(nodeid) {
1810 + if (!currentNode || currentNode._id != nodeid) return;
1811 + gotoDevice(nodeid, xxcurrentView, true);
1812 + }
1813 +
1814 + function getNodeRights(nodeid) {
1815 + var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
1816 + return mesh.links[userinfo._id].rights;
1817 + }
1818 +
1819 + var currentDevicePanel = 0;
1820 + var currentNode;
1821 + var powerTimelineNode = null;
1822 + var powerTimelineReq = null;
1823 + var powerTimelineUpdate = null;
1824 + var powerTimeline = null;
1825 + function getCurrentNode() { return currentNode; };
1826 + function gotoDevice(nodeid, panel, refresh) {
1827 +
1828 + // Remind the user to verify the email address
1829 + 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\" to change and verify an email address."); return; }
1830 +
1831 + // Remind the user to add two factor authentication
1832 + 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\" and look at the \"Account Security\" section."); return; }
1833 +
1834 + var node = getNodeFromId(nodeid);
1835 + if (node == null) { goBack(); return; }
1836 + var mesh = meshes[node.meshid];
1837 + if (mesh == null) { goBack(); return; }
1838 + var meshrights = mesh.links[userinfo._id].rights;
1839 + if (!currentNode || currentNode._id != node._id || refresh == true) {
1840 + currentNode = node;
1841 +
1842 + // Add node name
1843 + var nname = EscapeHtml(node.name);
1844 + if (nname.length == 0) { nname = '<i>' + "None" + '</i>'; }
1845 + if ((meshrights & 4) != 0) { nname = '<span onclick=showEditNodeValueDialog(0) style=cursor:pointer>' + nname + '</span>'; }
1846 + QH('p10deviceName', nname);
1847 +
1848 + // Node attributes
1849 + var x = '<table style=width:100%>';
1850 +
1851 + // Attribute: Mesh
1852 + x += addDeviceAttribute('<span>' + "Group" + '</span>', '<a onclick=goForward("' + node.meshid + '") style=cursor:pointer>' + EscapeHtml(meshes[node.meshid].name) + '</a>');
1853 +
1854 + // Attribute: Name
1855 + if (node.rname != null) { x += addDeviceAttribute('<span>' + "Name" + '</span>', '<span>' + EscapeHtml(node.rname) + '</span>'); }
1856 +
1857 + // Attribute: Host
1858 + if ((mesh.mtype == 1) || (node.name != node.host)) {
1859 + if ((meshrights & 4) != 0) {
1860 + if (node.host) {
1861 + x += addDeviceAttribute("Hostname", '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer>' + EscapeHtml(node.host) + '</span>');
1862 + } else {
1863 + x += addDeviceAttribute("Hostname", '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer><i>' + "None" + '</i></span>');
1864 + }
1865 + } else {
1866 + x += addDeviceAttribute("Hostname", EscapeHtml(node.host));
1867 + }
1868 + }
1869 +
1870 + // Attribute: Description
1871 + var description = node.desc ? EscapeHtml(node.desc) : '<i>' + "None" + '</i>';
1872 + if ((meshrights & 4) != 0) {
1873 + x += addDeviceAttribute("Description", '<span onclick=showEditNodeValueDialog(2) style=cursor:pointer>' + description + '</span>');
1874 + } else {
1875 + x += addDeviceAttribute("Description", description);
1876 + }
1877 +
1878 + // Attribute: Mesh Agent
1879 + var agentsStr = ["Inconnue", "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", "Inconnue", "Inconnue", "FreeBSD x86-64"];
1880 + if ((node.agent != null) && (node.agent.id != null) && (node.agent.ver != null)) {
1881 + var str = '';
1882 + if (node.agent.id <= agentsStr.length) { str = agentsStr[node.agent.id]; } else { str = agentsStr[0]; }
1883 + if (node.agent.ver != 0) { str += ' v' + node.agent.ver; }
1884 + x += addDeviceAttribute("Agent", str);
1885 + }
1886 +
1887 + // Attribute: Intel AMT
1888 + if (node.intelamt != null) {
1889 + var str = '';
1890 + var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activé") };
1891 + if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>' + nobreak("Etat inconnu") + '</i>, v' + node.intelamt.ver; } else
1892 +
1893 + if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '<i>' + "Activé" + '</i>'; }
1894 + else if ((node.intelamt.ver == null) || (node.intelamt.state == null)) { str += '<i>' + "Version et état inconnus" + '</i>'; }
1895 + else {
1896 + str += provisioningStates[node.intelamt.state];
1897 + if (node.intelamt.flags) { if (node.intelamt.flags & 2) { str = ' <span>' + "CCM" + '</span>'; } else if (node.intelamt.flags & 4) { str = ' <span>' + "ACM" + '</span>'; } }
1898 + str += (', v' + node.intelamt.ver);
1899 + }
1900 +
1901 + if (node.intelamt.tls == 1) { str += ', <span>' + "TLS" + '</span>'; }
1902 + if (node.intelamt.state == 2) {
1903 + if (node.intelamt.user == null || node.intelamt.user == '') {
1904 + if ((meshrights & 4) != 0) {
1905 + str += ', <i style=color:#FF0000;cursor:pointer onclick=editDeviceAmtSettings("' + node._id + '")>' + nobreak("No Credentials") + '</i>';
1906 + } else {
1907 + str += ', <i style=color:#FF0000>' + "No Credentials" + '</i>';
1908 + }
1909 + }
1910 + str += ' ';
1911 + if ((meshrights & 4) != 0) {
1912 + str += '<img src=images/link4.png height=10 width=10 style=cursor:pointer onclick=editDeviceAmtSettings("' + node._id + '")>';
1913 + }
1914 + }
1915 +
1916 + var meName = "Intel&reg; ME";
1917 + if (typeof node.intelamt.sku == 'number') {
1918 + if ((node.intelamt.sku & 8) != 0) { meName = "Intel&reg; AMT"; }
1919 + else if ((node.intelamt.sku & 16) != 0) { meName = "Intel&reg; SM"; }
1920 + }
1921 + x += addDeviceAttribute(meName, str);
1922 + }
1923 +
1924 + // Attribute: Mesh Agent Tag
1925 + if ((node.agent != null) && (node.agent.tag != null) && (node.agent.tag != 'mailto:')) {
1926 + var tag = EscapeHtml(node.agent.tag);
1927 + if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
1928 + x += addDeviceAttribute("Agent Tag", tag);
1929 + }
1930 +
1931 + // Attribute: Intel AMT
1932 + //if (node.intelamt && node.intelamt.user) { x += addDeviceAttribute('Intel&reg; AMT', node.intelamt.user); }
1933 +
1934 + // Attribute: Connectivity (Only show this if more than just the agent is connected).
1935 + var connectivity = node.conn;
1936 + if (connectivity && connectivity > 1) {
1937 + var cstate = [];
1938 + if ((node.conn & 1) != 0) cstate.push('<span>' + "Agent" + '</span>');
1939 + if ((node.conn & 2) != 0) cstate.push('<span>' + "Intel&reg; AMT CIRA" + '</span>');
1940 + else if ((node.conn & 4) != 0) cstate.push('<span>' + "Intel&reg; AMT" + '</span>');
1941 + if ((node.conn & 8) != 0) cstate.push('<span>' + "Agent Relay" + '</span>');
1942 + if ((node.conn & 16) != 0) cstate.push('<span>' + "MQTT" + '</span>');
1943 + x += addDeviceAttribute("Connectivity", cstate.join(', '));
1944 + }
1945 +
1946 + // Node tags
1947 + var groupingTags = '<i>' + "None" + '</i>';
1948 + if (node.tags != null) { groupingTags = ''; for (var i in node.tags) { groupingTags += '<span style="background-color:lightgray;padding:3px;margin-right:4px;border-radius:5px">' + node.tags[i] + '</span>'; } }
1949 + if ((meshrights & 4) != 0) {
1950 + x += addDeviceAttribute("Tags", '<span onclick=showEditNodeValueDialog(3) style=cursor:pointer>' + groupingTags + '</span>');
1951 + } else {
1952 + x += addDeviceAttribute("Tags", groupingTags);
1953 + }
1954 +
1955 + x += '</table><br />';
1956 + // Show action button, only show if we have permissions 4, 8, 64
1957 + if ((meshrights & 76) != 0) { x += '<input type=button value=Actions onclick=deviceActionFunction() />'; }
1958 + //x += '<input type=button value=Notes onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
1959 + //if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += '<input type=button value=Toast onclick=deviceToastFunction() />'; }
1960 + QH('p10html', x);
1961 +
1962 + // Show node last 7 days timeline
1963 + //drawDeviceTimeline();
1964 + setupFiles();
1965 +
1966 + // Show bottom buttons
1967 + x = '<div style=float:right;font-size:x-small;margin-right:10px>';
1968 + if ((meshrights & 4) != 0) x += '<a style=cursor:pointer onclick=p10showDeleteNodeDialog("' + node._id + '")>' + "Delete Device" + '</a>';
1969 + x += '</div><div style=font-size:x-small>';
1970 + //if (mesh.mtype == 2) x += '<a style=cursor:pointer onclick=p10showNodeNetInfoDialog("' + node._id + '")>Interfaces</a>&nbsp;';
1971 + //if (xxmap != null) x += '<a style=cursor:pointer onclick=p10showNodeLocationDialog("' + node._id + '")>Location</a>&nbsp;';
1972 + x += '</div><br>'
1973 +
1974 + QH('p10html3', x);
1975 +
1976 + // Set the node power state
1977 + var powerstate = PowerStateStr(node.state);
1978 + //if (node.state == 0) { powerstate = 'Unknown State'; }
1979 + if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px>' + "Mesh Agent" + '</span>'; }
1980 + if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px>' + "Intel&reg; AMT connected" + '</span>'; }
1981 + else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px>' + "Intel&reg; AMT detected" + '</span>'; }
1982 + if ((connectivity & 16) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px>' + "MQTT channel connected" + '</span>'; }
1983 + QH('MainComputerState', powerstate);
1984 +
1985 + // Set the node icon
1986 + QH('MainComputerImage', '<div class="i' + node.icon + '"></div>');
1987 +
1988 + // Request the power timeline
1989 + if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { QH('p10html2', ''); powerTimelineReq = currentNode._id; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
1990 + }
1991 + setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
1992 + if (!panel) panel = 10;
1993 + go(panel);
1994 +
1995 + // Update the footer menu
1996 + setupDeviceMenu();
1997 + }
1998 +
1999 + function deviceToastFunction() {
2000 + if (xxdialogMode) return;
2001 + setDialogMode(2, "Device Toast", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
2002 + }
2003 +
2004 + function deviceToastFunctionEx() {
2005 + meshserver.send({ action: 'toast', nodeids: [currentNode._id], title: 'MeshCentral', msg: Q('d2devToast').value });
2006 + }
2007 +
2008 + function setupDeviceMenu(op, obj) {
2009 + var meshrights = 0;
2010 + if (currentNode) { meshrights = meshes[currentNode.meshid].links[userinfo._id].rights; }
2011 + if (op != null) { currentDevicePanel = op; }
2012 + QV('p10general', currentDevicePanel == 0);
2013 + QV('p10desktop', currentDevicePanel == 1); // Show if we have remote control rights or desktop view only rights
2014 + QV('p10files', currentDevicePanel == 2);
2015 + var menus = [];
2016 + if (currentDevicePanel != 0) { menus.push({ n: 'General', f: 'setupDeviceMenu(0)' }); }
2017 + if ((currentDevicePanel != 1) &&
2018 + (currentNode != null) &&
2019 + ((meshrights & 8) || (meshrights & 256)) &&
2020 + (((meshes[currentNode.meshid].mtype == 1) && ((typeof currentNode.intelamt.sku !== 'number') || ((currentNode.intelamt.sku & 8) != 0))) || (currentNode.agent && (currentNode.agent.caps & 1)))
2021 + ) { menus.push({ n: 'Desktop', f: 'setupDeviceMenu(1)' }); }
2022 + if ((currentDevicePanel != 2) && (currentNode != null) && (meshrights & 8) && ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0)) && ((currentNode.mtype == 2) && (currentNode.agent.caps & 4))) { menus.push({ n: 'Files', f: 'setupDeviceMenu(2)' }); }
2023 + updateFooterMenu(menus);
2024 + }
2025 +
2026 + function deviceActionFunction() {
2027 + if (xxdialogMode) return;
2028 + var meshrights = meshes[currentNode.meshid].links[userinfo._id].rights;
2029 + var x = "Select an operation to perform on this device." + '<br /><br />';
2030 + var y = '<select id=d2deviceop style=float:right;width:170px>';
2031 + if ((meshrights & 64) != 0) { y += '<option value=100>' + "Wake-up" + '</option>'; } // Wake-up permission
2032 + if ((meshrights & 8) != 0) { y += '<option value=4>' + "Sleep" + '</option><option value=3>' + "Reset" + '</option><option value=2>' + "Power off" + '</option>'; } // Remote control permission
2033 + y += '</select>';
2034 + x += addHtmlValue("Operation", y);
2035 + setDialogMode(2, "Device Action", 3, deviceActionFunctionEx, x);
2036 + }
2037 +
2038 + function deviceActionFunctionEx() {
2039 + var op = Q('d2deviceop').value;
2040 + if (op == 100) {
2041 + // Device wake
2042 + meshserver.send({ action: 'wakedevices', nodeids: [currentNode._id] });
2043 + } else {
2044 + // Power operation
2045 + meshserver.send({ action: 'poweraction', nodeids: [currentNode._id], actiontype: op });
2046 + }
2047 + }
2048 +
2049 + // Look to see if we need to update the device timeline
2050 + function updateDeviceTimeline() {
2051 + if ((meshserver.State != 2) || (powerTimelineNode == null) || (powerTimelineUpdate == null) || (currentNode == null)) return;
2052 + if ((powerTimelineNode == powerTimelineReq) && (currentNode._id == powerTimelineNode) && (powerTimelineUpdate < Date.now())) { powerTimelineUpdate = null; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
2053 + }
2054 +
2055 + // Draw device power bars. The bars are 766px wide.
2056 + function drawDeviceTimeline() {
2057 + var timeline = null, now = Date.now();
2058 + if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
2059 +
2060 + // Calculate when the timeline starts
2061 + var d = new Date();
2062 + d.setHours(0, 0, 0, 0);
2063 + d = new Date(d.getTime() - (1000 * 60 * 60 * 24 * 6));
2064 + var timelineStart = d.getTime();
2065 +
2066 + // De-compact the timeline
2067 + var timeline2 = [];
2068 + if (timeline != null && timeline.length > 1) {
2069 + timeline2.push([0, timeline[1], timeline[0]]); // Start, End, Power
2070 + var ct = timeline[1];
2071 + for (var i = 2; i < timeline.length; i += 2) {
2072 + var power = timeline[i], dt = now;
2073 + if (timeline.length > (i + 1)) { dt = timeline[i + 1]; }
2074 + timeline2.push([ct, ct + dt, power]); // Start, End, Power
2075 + ct = ct + dt;
2076 + }
2077 + }
2078 +
2079 + // Draw the timeline
2080 + var x = '', count = 1, date = new Date();
2081 + var totalWidth = Q('masthead').offsetWidth - (90 + 9 + 9 + 14); // Compute the total width of the power bar
2082 + date.setHours(0, 0, 0, 0);
2083 + for (var i = 0; i < 7; i++) {
2084 + var datavalue = '', start = date.getTime(), end = start + (1000 * 60 * 60 * 24);
2085 + for (var j in timeline2) {
2086 + var block = timeline2[j];
2087 + if (isTimeBlockInside(start, end, block[0], block[1]) == true) {
2088 + var ts = Math.max(start, block[0]);
2089 + var te = Math.min(Math.min(end, block[1]), now);
2090 + var width = Math.round(((te - ts) * totalWidth) / 86400000);
2091 + if (width > 0) { datavalue += '<div style=display:table-cell;width:' + width + 'px;background-color:' + powerColor(block[2]) + ';height:16px></div>'; }
2092 + }
2093 + }
2094 + x += '<tr style=' + (((count % 2) == 0) ? 'background-color:#DDD' : '') + '><td><div>&nbsp;' + printDate(date) + '<div></div></div></td><td><div>' + datavalue + '</div></td></tr>';
2095 + ++count;
2096 + date = new Date(date.getTime() - (1000 * 60 * 60 * 24)); // Substract one day
2097 + }
2098 + QH('p10html2', '<table style="color:black;background-color:#EEE;border-color:#AAA;border-width:1px;border-style:solid;border-collapse:collapse;width:calc(100% - 18px);margin:9px" border=0 cellpadding=2 cellspacing=0><tbody><tr style=background-color:#AAAAAA;font-weight:bold><th scope=col style=text-align:center;width:90px>Day</th><th scope=col style=text-align:center>Power State</th></tr>' + x + '</tbody></table>');
2099 + }
2100 +
2101 + // Return a color for the given power state
2102 + function powerColor(x) { if (x < powerColorTable.length) { return powerColorTable[x]; } return 'yellow'; }
2103 +
2104 + // Return true if the time block is visible within the start/end period
2105 + function isTimeBlockInside(start, end, blockStart, blockEnd) {
2106 + if ((blockStart < start) && (blockEnd > end)) return true; // Block is wider than timespan
2107 + if ((blockStart > start) && (blockStart < end)) return true;
2108 + if ((blockEnd > start) && (blockEnd < end)) return true;
2109 + return false;
2110 + }
2111 +
2112 + function addDeviceAttribute(name, value) {
2113 + return '<tr><td style=width:100px;color:gray>' + name + '</td><td style=overflow:hidden>' + value + '</td></tr>';
2114 + }
2115 +
2116 + function editDeviceAmtSettings(nodeid, func) {
2117 + if (xxdialogMode) return;
2118 + var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
2119 + if ((meshrights & 4) == 0) return;
2120 + x += addHtmlValue("Nom d'utilisateur", '<input id=dp10username style=width:170px maxlength=32 autocomplete=nope placeholder="admin" onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
2121 + x += addHtmlValue("Password", '<input id=dp10password type=password style=width:170px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
2122 + x += addHtmlValue("Security", '<select id=dp10tls style=width:176px><option value=0>' + "No TLS security" + '</option><option value=1>' + "Sécurité TLS requise" + '</option></select>');
2123 + if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
2124 + setDialogMode(2, "Edit Intel&reg; AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func });
2125 + if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
2126 + Q('dp10tls').value = node.intelamt.tls;
2127 + validateDeviceAmtSettings();
2128 + }
2129 +
2130 + function validateDeviceAmtSettings() {
2131 + QE('idx_dlgOkButton', passwordcheck(Q('dp10password').value));
2132 + }
2133 +
2134 + function editDeviceAmtSettingsEx(button, tag) {
2135 + if (button == 2) {
2136 + // Delete button pressed, remove credentials
2137 + meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: '', pass: '' } });
2138 + } else {
2139 + // Change Intel AMT credentials
2140 + var amtuser = Q('dp10username').value;
2141 + if (amtuser == '') amtuser = 'admin';
2142 + var amtpass = Q('dp10password').value;
2143 + if (amtpass == '') amtuser = '';
2144 + meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
2145 + tag.node.intelamt.user = amtuser;
2146 + tag.node.intelamt.tls = Q('dp10tls').value;
2147 + if (tag.func) { setTimeout(tag.func, 300); }
2148 + }
2149 + }
2150 +
2151 + function p10showDeleteNodeDialog(nodeid) {
2152 + if (xxdialogMode) return;
2153 + setDialogMode(2, "Delete Node", 3, p10showDeleteNodeDialogEx, format("Delete {0}?", EscapeHtml(currentNode.name)) + '<br /><br /><input id=p10check type=checkbox onchange=p10validateDeleteNodeDialog() />' + "Confirm", nodeid);
2154 + p10validateDeleteNodeDialog();
2155 + }
2156 +
2157 + function p10validateDeleteNodeDialog() {
2158 + QE('idx_dlgOkButton', Q('p10check').checked);
2159 + }
2160 +
2161 + function p10showDeleteNodeDialogEx(buttons, nodeid) {
2162 + meshserver.send({ action: 'removedevices', nodeids: [nodeid] });
2163 + }
2164 +
2165 + function p10showiconselector() {
2166 + if (xxdialogMode) return;
2167 + var mesh = meshes[currentNode.meshid];
2168 + var meshrights = mesh.links[userinfo._id].rights;
2169 + if ((meshrights & 4) == 0) return;
2170 +
2171 + var x = '<table align=center><td>';
2172 + x += '<div style=display:inline-block class=i1 onclick=p10setIcon(1)></div>';
2173 + x += '<div style=display:inline-block class=i2 onclick=p10setIcon(2)></div>';
2174 + x += '<div style=display:inline-block class=i3 onclick=p10setIcon(3)></div><br>';
2175 + x += '<div style=display:inline-block class=i4 onclick=p10setIcon(4)></div>';
2176 + x += '<div style=display:inline-block class=i5 onclick=p10setIcon(5)></div>';
2177 + x += '<div style=display:inline-block class=i6 onclick=p10setIcon(6)></div></table>';
2178 + setDialogMode(2, "Icon Selection", 0, null, x);
2179 + QV('id_dialogclose', true);
2180 + }
2181 +
2182 + function p10setIcon(icon) {
2183 + setDialogMode(0);
2184 + meshserver.send({ action: 'changedevice', nodeid: currentNode._id, icon: icon });
2185 + }
2186 +
2187 + var showEditNodeValueDialog_modes = ["Device Name", "Hostname", "Description", "Tags"];
2188 + var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc', 'tags'];
2189 + var showEditNodeValueDialog_modes3 = ['', '', '', "Group1, Group2, Group3"];
2190 + function showEditNodeValueDialog(mode) {
2191 + if (xxdialogMode) return;
2192 + var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:170px maxlength=64 placeholder="' + showEditNodeValueDialog_modes3[mode] + '" onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
2193 + setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode);
2194 + var v = currentNode[showEditNodeValueDialog_modes2[mode]];
2195 + if (v == null) v = '';
2196 + if (Array.isArray(v)) { v = v.join(', '); }
2197 + Q('dp10devicevalue').value = v;
2198 + p10editdevicevalueValidate();
2199 + Q('dp10devicevalue').focus();
2200 + }
2201 +
2202 + function showEditNodeValueDialogEx(button, mode) {
2203 + var x = { action: 'changedevice', nodeid: currentNode._id };
2204 + x[showEditNodeValueDialog_modes2[mode]] = Q('dp10devicevalue').value;
2205 + meshserver.send(x);
2206 + }
2207 +
2208 + function p10editdevicevalueValidate(mode, e) {
2209 + var x = ((mode > 1) || (Q('dp10devicevalue').value.length > 0));
2210 + QE('idx_dlgOkButton', x);
2211 + if ((e != null) && (x == true) && (e.keyCode == 13)) { dialogclose(1); }
2212 + }
2213 +
2214 + //
2215 + // DESKTOP
2216 + //
2217 +
2218 + var desktop;
2219 + var desktopNode;
2220 + var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 50 };
2221 + function setupDesktop() {
2222 + // Setup the remote desktop
2223 + if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); desktopNode = null; desktop = null; }
2224 +
2225 + // If the device desktop is already connected in multi-desktop, use that.
2226 + if ((desktopNode != currentNode) || (desktop == null)) {
2227 + // Device is not already connected, just setup a blank canvas
2228 + QH('DeskParent', '<canvas id=Desk width=640 height=200 style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
2229 + desktopNode = currentNode;
2230 + // Setup the mouse wheel
2231 + Q('Desk').addEventListener('DOMMouseScroll', function (e) { return dmousewheel(e); });
2232 + Q('Desk').addEventListener('mousewheel', function (e) { return dmousewheel(e); });
2233 + }
2234 + desktopNode = currentNode;
2235 + updateDesktopButtons();
2236 +
2237 + // On some browsers like IE, we can't save screen shots. Hide the scheenshot/capture buttons.
2238 + if (!Q('Desk')['toBlob']) { QV('deskSaveBtn', false); }
2239 + }
2240 +
2241 + // Show and enable the right buttons
2242 + function updateDesktopButtons() {
2243 + var mesh = meshes[currentNode.meshid];
2244 + var deskState = 0;
2245 + if (desktop != null) { deskState = desktop.State; }
2246 + var meshrights = mesh.links[userinfo._id].rights;
2247 +
2248 + // Show the right buttons
2249 + QV('disconnectbutton1', (deskState != 0));
2250 + QV('connectbutton1', (deskState == 0) && (mesh.mtype == 2) && ((meshrights & 8) || (meshrights & 256)));
2251 + QV('connectbutton1h',
2252 + (deskState == 0) &&
2253 + (meshrights & 8) &&
2254 + ((mesh.mtype == 1) ||
2255 + (currentNode.intelamt != null) &&
2256 + ((currentNode.intelamt.state == 2) &&
2257 + (currentNode.intelamt.ver != null) &&
2258 + (typeof currentNode.intelamt.sku == 'number') &&
2259 + ((currentNode.intelamt.sku & 8) != 0))
2260 + )
2261 + );
2262 +
2263 + // Show the right settings
2264 + QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == 0) || (desktop.contype == 2)));
2265 + QV('d7meshkvm', (mesh.mtype == 2) && ((deskState == false) || (desktop.contype == 1)));
2266 +
2267 + // Enable buttons
2268 + var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable remote desktop
2269 + QE('connectbutton1', online);
2270 + var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
2271 + QE('connectbutton1h', hwonline);
2272 + //QE('deskSaveBtn', deskState == 3);
2273 + //QV('DeskCAD', meshrights & 8);
2274 + //QE('DeskCAD', deskState == 3);
2275 + //QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5));
2276 + //QE('DeskWD', deskState == 3);
2277 + //QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5));
2278 + //QE('deskkeys', deskState == 3);
2279 + //QE('DeskToolsButton', online);
2280 + QV('DeskToastButton', ((meshrights & 16384) != 0) && (currentNode.agent) && (currentNode.agent.id < 5) && (meshrights & 8));
2281 + //QE('DeskToastButton', online);
2282 + QV('deskActionsBtn', meshrights & 8);
2283 + Q('DeskControl').checked = ((meshrights & 8) != 0);
2284 + if (online == false) QV('DeskTools', false);
2285 + }
2286 +
2287 + function connectDesktop(e, contype) {
2288 + setSessionActivity();
2289 + if (desktop == null) {
2290 + desktopNode = currentNode;
2291 + if (contype == 2) {
2292 + // Setup the Intel AMT remote desktop
2293 + if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
2294 + desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
2295 + desktop.debugmode = debugmode;
2296 + desktop.onStateChanged = onDesktopStateChange;
2297 + desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
2298 + desktop.m.useZRLE = (desktopsettings.encoding < 3);
2299 + desktop.m.showmouse = desktopsettings.showmouse;
2300 + desktop.m.onScreenSizeChange = deskAdjust;
2301 + desktop.Start(desktopNode._id, 16994, '*', '*', 0);
2302 + desktop.contype = 2;
2303 + } else {
2304 + // Setup the Mesh Agent remote desktop
2305 + desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
2306 + desktop.debugmode = debugmode;
2307 + desktop.m.debugmode = debugmode;
2308 + desktop.attemptWebRTC = attemptWebRTC;
2309 + desktop.onStateChanged = onDesktopStateChange;
2310 + desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
2311 + desktop.m.ScalingLevel = desktopsettings.scaling;
2312 + desktop.m.FrameRateTimer = desktopsettings.framerate;
2313 + desktop.m.onDisplayinfo = deskDisplayInfo;
2314 + desktop.m.onScreenSizeChange = deskAdjust;
2315 + desktop.Start(desktopNode._id);
2316 + desktop.contype = 1;
2317 + }
2318 + } else {
2319 + // Disconnect and clean up the remote desktop
2320 + desktop.Stop();
2321 + desktopNode = desktop = null;
2322 + }
2323 + }
2324 +
2325 + function onDesktopStateChange(xdesktop, state) {
2326 + var xstate = state;
2327 + if ((xstate == 3) && (xdesktop.contype == 2)) { xstate++; }
2328 + var str = StatusStrs[xstate];
2329 + if ((desktop != null) && (desktop.webRtcActive == true)) { str += ", WebRTC"; }
2330 + //if (desktop.m.stopInput == true) { str += ', Loopback'; }
2331 + QH('deskstatus', str);
2332 + switch (state) {
2333 + case 0:
2334 + // Disconnect and clean up the remote desktop
2335 + desktop.Stop();
2336 + desktopNode = desktop = null;
2337 + QV('termdisplays', false);
2338 + if (fullscreen == true) { deskToggleFull(); }
2339 + break;
2340 + case 2:
2341 + break;
2342 + default:
2343 + //console.log('Unknown onDesktopStateChange state', state);
2344 + break;
2345 + }
2346 + updateDesktopButtons();
2347 + deskAdjust();
2348 + setTimeout(deskAdjust, 50);
2349 + }
2350 +
2351 + function showDesktopSettings() {
2352 + if (xxdialogMode) return;
2353 + applyDesktopSettings();
2354 + updateDesktopButtons();
2355 + setDialogMode(7, "Remote Desktop Settings", 3, showDesktopSettingsChanged);
2356 + }
2357 +
2358 + function showDesktopSettingsChanged() {
2359 + desktopsettings.encoding = d7desktopmode.value;
2360 + desktopsettings.showfocus = d7showfocus.checked;
2361 + desktopsettings.showmouse = d7showcursor.checked;
2362 + desktopsettings.quality = d7bitmapquality.value;
2363 + desktopsettings.scaling = d7bitmapscaling.value;
2364 + desktopsettings.framerate = d7framelimiter.value;
2365 + localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
2366 + applyDesktopSettings();
2367 + if (desktop) {
2368 + if (desktop.contype == 1) {
2369 + if (desktop.State != 0) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
2370 + }
2371 + if (desktop.contype == 2) {
2372 + if (desktop.State != 0) { desktop.Stop(); setTimeout(function () { connectDesktop(null, 2); }, 50); }
2373 + }
2374 + }
2375 + }
2376 +
2377 + function applyDesktopSettings() {
2378 + var r = '', ops = (features & 512) ? [90, 70, 50, 40, 30, 20, 10, 5, 1] : [50, 40, 30, 20, 10, 5, 1];
2379 + for (var i in ops) { r += '<option value=' + ops[i] + '>' + ops[i] + '%</option>'; }
2380 + QH('d7bitmapquality', r);
2381 + d7desktopmode.value = desktopsettings.encoding;
2382 + d7showfocus.checked = desktopsettings.showfocus;
2383 + d7showcursor.checked = desktopsettings.showmouse;
2384 + d7bitmapquality.value = 40; // Default value
2385 + if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
2386 + d7bitmapscaling.value = desktopsettings.scaling;
2387 + if (desktopsettings.framerate) { d7framelimiter.value = desktopsettings.framerate; }
2388 + }
2389 +
2390 + var fullscreen = false;
2391 + /*
2392 + function deskToggleFull() {
2393 + fullscreen = !fullscreen;
2394 + QV('mastheadx', !fullscreen);
2395 + QV('masthead', !fullscreen);
2396 + QV('topbar', !fullscreen);
2397 + QV('p11deviceNameHeader', !fullscreen);
2398 + QV('footer', !fullscreen);
2399 + QV('column_l_bottomgap', !fullscreen);
2400 + QV('idx_deskFullBtn2', fullscreen);
2401 + QV('deskFullBtn', !fullscreen);
2402 + if (fullscreen) {
2403 + QS('container').width = '100%';
2404 + QS('container')['border-right'] = '0';
2405 + QS('container')['border-left'] = '0';
2406 + QS('column_l').padding = '0';
2407 + QS('column_l').width = '100%';
2408 + } else {
2409 + QS('container').width = '960px';
2410 + QS('container')['border-right'] = '1px solid #b7b7b7';
2411 + QS('container')['border-left'] = '1px solid #b7b7b7';
2412 + QS('column_l').padding = '0 15px';
2413 + QS('column_l').width = '930px';
2414 + toggleFullScreen();
2415 + }
2416 + deskAdjust();
2417 + }
2418 + */
2419 +
2420 + function deskAdjust() {
2421 + var x = (Q('DeskParent').clientHeight - Q('Desk').clientHeight) / 2;
2422 + if (x < 0) {
2423 + var mh = Q('DeskParent').clientHeight, mw = 9999;
2424 + if (desktop) { mw = (desktop.m.width / desktop.m.height) * mh; }
2425 + QS('Desk')['max-height'] = mh + 'px';
2426 + QS('Desk')['max-width'] = mw + 'px';
2427 + x = 0;
2428 + } else {
2429 + QS('Desk')['max-height'] = null;
2430 + QS('Desk')['max-width'] = null;
2431 + }
2432 + QS('Desk')['margin-top'] = x + 'px';
2433 + QS('Desk')['margin-bottom'] = x + 'px';
2434 + }
2435 +
2436 + // Remote desktop special key combos for Windows
2437 + function deskSendKeys() {
2438 + if (xxdialogMode || desktop == null || desktop.State != 3) return;
2439 + var ks = Q('deskkeys').value;
2440 + if (ks == 0) { // WIN+Down arrow
2441 + if (desktop.contype == 2) {
2442 + 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
2443 + } else {
2444 + 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
2445 + }
2446 + } else if (ks == 1) { // WIN+Up arrow
2447 + if (desktop.contype == 2) {
2448 + 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
2449 + } else {
2450 + 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
2451 + }
2452 + } else if (ks == 2) { // WIN+L arrow
2453 + if (desktop.contype == 2) {
2454 + desktop.m.sendkey([[0xffe7, 1], [0x6c, 1], [0x6c, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, 'l' press, 'l' release, Meta-left release
2455 + } else {
2456 + desktop.sendCtrlMsg('{"action":"lock"}');
2457 + //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
2458 + //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXDOWN, 0x5B);
2459 + //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.DOWN, 76);
2460 + //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.UP, 76);
2461 + //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXUP, 0x5B);
2462 + }
2463 + } else if (ks == 3) { // WIN+M arrow
2464 + if (desktop.contype == 2) {
2465 + desktop.m.sendkey([[0xffe7, 1], [0x6d, 1], [0x6d, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, 'm' press, 'm' release, Meta-left release
2466 + } else {
2467 + 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
2468 + }
2469 + } else if (ks == 4) { // Shift+WIN+M arrow
2470 + if (desktop.contype == 2) {
2471 + 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
2472 + } else {
2473 + 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
2474 + }
2475 + } else if (ks == 5) { // WIN
2476 + if (desktop.contype == 2) {
2477 + desktop.m.sendkey([[0xffe7, 1], [0xffe7, 0]]); // Intel AMT: Meta-left down, Meta-left release
2478 + } else {
2479 + desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, L-Winkey release
2480 + }
2481 + } else if (ks == 6) { // WIN+R
2482 + if (desktop.contype == 2) {
2483 + desktop.m.sendkey([[0xffe7, 1], [0x72, 1], [0x72, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, 'r' press, 'r' release, Meta-left release
2484 + } else {
2485 + 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
2486 + }
2487 + } else if (ks == 7) { // ALT-F4
2488 + if (desktop.contype == 2) {
2489 + desktop.m.sendkey([[0xffe9, 1], [0xffc1, 1], [0xffc1, 0], [0xffe9, 0]]); // Intel AMT: Alt down, 'F4' press, 'F4' release, Alt release
2490 + } else {
2491 + 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
2492 + }
2493 + } else if (ks == 8) { // CTRL-W
2494 + if (desktop.contype == 2) {
2495 + desktop.m.sendkey([[0xffe3, 1], [0x77, 1], [0x77, 0], [0xffe3, 0]]); // Intel AMT: Ctrl down, 'w' press, 'w' release, Ctrl release
2496 + } else {
2497 + 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
2498 + }
2499 + } else if (ks == 9) { // ALT-TAB
2500 + if (desktop.contype == 2) {
2501 + desktop.m.sendkey([[0xffe9, 1], [0xff09, 1], [0xff09, 0], [0xffe9, 0]]); // Intel AMT: Alt down, 'TAB' press, 'TAB' release, Alt release
2502 + } else {
2503 + 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
2504 + }
2505 + } else if (ks == 10) { // CTRL-ALT-DEL
2506 + desktop.m.sendcad();
2507 + } else if (ks == 11) { // TAB
2508 + if (desktop.contype == 2) {
2509 + desktop.m.sendkey([[0xff09, 1], [0xff09, 0]]); // Intel AMT: 'TAB' press, 'TAB' release
2510 + } else {
2511 + desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.DOWN, 9], [desktop.m.KeyAction.UP, 9]]); // MeshAgent: 'TAB' press, 'TAB' release
2512 + }
2513 + }
2514 + }
2515 +
2516 + function sendSpecialKeys() {
2517 + if (xxdialogMode || desktop == null || desktop.State != 3) return;
2518 + setDialogMode(3, "Special Keys", 3, deskSendKeys);
2519 + }
2520 +
2521 + // Send CTRL-ALT-DEL
2522 + /*
2523 + function sendCAD() {
2524 + if (xxdialogMode || desktop == null || desktop.State != 3) return;
2525 + desktop.m.sendcad();
2526 + }
2527 + */
2528 +
2529 + // Toggle soft keyboard
2530 + function toggleSoftKeys(x) {
2531 + QV('DeskSoftInput', x == 1);
2532 + if (x == 1) { Q('DeskSoftInput').focus(); }
2533 + }
2534 +
2535 + // Show process dialogs
2536 + function toggleDeskTools() {
2537 + setSessionActivity();
2538 + if (xxdialogMode) return;
2539 + if (QS('DeskTools').display == 'none') {
2540 + QV('DeskTools', true);
2541 + Q('DeskTools').nodeid = currentNode._id;
2542 + refreshDeskTools();
2543 + } else {
2544 + QV('DeskTools', false);
2545 + }
2546 + }
2547 +
2548 + // Refresh all of the desktop tool panels
2549 + function refreshDeskTools() {
2550 + setSessionActivity();
2551 + QV('DeskToolsRefreshButton', false);
2552 + setTimeout(refreshDeskToolsEx, 500);
2553 + meshserver.send({ action: 'msg', type: 'ps', nodeid: currentNode._id });
2554 + }
2555 + function refreshDeskToolsEx() { QV('DeskToolsRefreshButton', true); }
2556 + var deskTools = { sort: 1, msg: null };
2557 + function sortProcess(sort) { deskTools.sort = sort; showDeskToolsProcesses(deskTools.msg); }
2558 + function sortProcessPid(a, b) { if (a.p > b.p) return 1; if (a.p < b.p) return (-1); return 0; }
2559 + function sortProcessName(a, b) { if (a.d > b.d) return 1; if (a.d < b.d) return (-1); return 0; }
2560 + function showDeskToolsProcesses(message) {
2561 + deskTools.msg = message;
2562 + if (message == null) { QH('DeskToolsProcesses', ''); return; }
2563 + if (Q('DeskTools').nodeid != message.nodeid) return;
2564 + var p = [], processes = null;
2565 + try { processes = JSON.parse(message.value); } catch (e) { }
2566 + console.log(processes);
2567 + if (processes != null) {
2568 + for (var pid in processes) { p.push({ p: parseInt(pid), c: processes[pid].cmd, d: processes[pid].cmd.toLowerCase(), u: processes[pid].user }); }
2569 + if (deskTools.sort == 0) { p.sort(sortProcessPid); } else if (deskTools.sort == 1) { p.sort(sortProcessName); }
2570 + var x = '';
2571 + for (var i in p) { if (p[i].p != 0) { x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + p[i].p + '</div><a style=float:right;padding-right:5px;cursor:pointer onclick=stopProcess(' + p[i].p + ',"' + p[i].c + '")><img width=10 height=10 src="images/trash.png"></a><div style=float:right;padding-right:5px>' + (p[i].u ? p[i].u : '') + '</div><div>' + p[i].c + '</div></div>'; } }
2572 + QH('DeskToolsProcesses', x);
2573 + }
2574 + }
2575 +
2576 + // Save the desktop image to file
2577 + function deskSaveImage() {
2578 + setSessionActivity();
2579 + if (xxdialogMode || desktop == null || desktop.State != 3) return;
2580 + var d = new Date(), n = 'Desktop-' + currentNode.name + '-' + d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + "-" + ("0" + d.getHours()).slice(-2) + '-' + ('0' + d.getMinutes()).slice(-2);
2581 + Q('Desk')['toBlob'](function (blob) { saveAs(blob, n + '.jpg'); });
2582 + }
2583 +
2584 + function deskDisplayInfo(sender, info, selDisplay, selItem) {
2585 + var txt = Q('termdisplays').value;
2586 + if (info.length > 0) { var options = ''; for (var x in info) { options += '<option' + ((txt == info[x]) ? ' selected' : '') + '>' + info[x] + '</option>'; } QH('termdisplays', options); }
2587 + QV('termdisplays', info.length > 0);
2588 + }
2589 +
2590 + function deskGetDisplayNumbers(e) { desktop.m.GetDisplayNumbers(); }
2591 +
2592 + function deskSetDisplay(e) {
2593 + setSessionActivity();
2594 + var display = 0, txt = Q('termdisplays').value;
2595 + if (txt == "All Displays") display = 65535; else display = parseInt(txt.substring(8));
2596 + desktop.m.SetDisplay(display);
2597 + }
2598 +
2599 + function dmousedown(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) desktop.m.mousedown(e) }
2600 + function dmouseup(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) desktop.m.mouseup(e) }
2601 + function dmousemove(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) desktop.m.mousemove(e) }
2602 + function dmousewheel(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null) && desktop.m.mousewheel) { desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
2603 + function drotate(x) { if (!xxdialogMode && desktop != null) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); deskAdjust(); } }
2604 + function stopProcess(id, name) { setDialogMode(2, "Process Control", 3, stopProcessEx, format("Stop process #{0} \"{1}\"?", id, name), id); return false; }
2605 + function stopProcessEx(buttons, tag) { meshserver.send({ action: 'msg', type: 'pskill', nodeid: currentNode._id, value: tag }); setTimeout(refreshDeskTools, 300); }
2606 +
2607 + //
2608 + // FILES
2609 + //
2610 +
2611 + var filesNode;
2612 + function setupFiles() {
2613 + // Setup the files tab
2614 + var samenode = (filesNode == currentNode);
2615 + filesNode = currentNode;
2616 + var online = ((filesNode.conn & 1) != 0) ? true : false; // If Agent (1) connected, enable Terminal
2617 + QE('p13Connect', online);
2618 + if (((samenode == false) || (online == false)) && files) { files.Stop(); files = null; }
2619 + }
2620 +
2621 + function onFilesStateChange(xfiles, state) {
2622 + setSessionActivity();
2623 + p13Connect.value = (state == 0) ? "Connect" : "Disconnect";
2624 + var str = StatusStrs[state];
2625 + if (files.webRtcActive == true) { str += ", WebRTC"; }
2626 + Q('p13Status').textContent = str;
2627 + switch (state) {
2628 + case 0:
2629 + // Disconnected, clear the files
2630 + QH('p13files', '');
2631 + p13filetree = null;
2632 + p13filetreelocation = [];
2633 + QH('p13currentpath', '');
2634 + QE('p13FolderUp', false);
2635 + p13setActions();
2636 + if (files != null) { files.Stop(); files = null; }
2637 + break;
2638 + case 3:
2639 + p13targetpath = '';
2640 + files.sendText({ action: 'ls', reqid: 1, path: '' });
2641 + break;
2642 + default:
2643 + //console.log('Unknown onFilesStateChange state', state);
2644 + break;
2645 + }
2646 + }
2647 +
2648 + function CreateRemoteFiles(onFileUpdate) {
2649 + var obj = { protocol: 5 };
2650 + obj.onFileUpdate = onFileUpdate;
2651 + obj.xxStateChange = function (state) { }
2652 + obj.ProcessData = function (data) { obj.onFileUpdate(data); }
2653 + return obj;
2654 + }
2655 +
2656 + // Debug Only
2657 + var autoConnectFilesTimer = null;
2658 + function autoConnectFiles(e) { if (autoConnectFilesTimer == null) { autoConnectFilesTimer = setInterval(connectFiles, 100); } else { clearInterval(autoConnectFilesTimer); autoConnectFilesTimer = null; } }
2659 +
2660 + function connectFiles(e) {
2661 + if (!files) {
2662 + // Setup a mesh agent files
2663 + files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
2664 + files.attemptWebRTC = attemptWebRTC;
2665 + files.onStateChanged = onFilesStateChange;
2666 + files.Start(filesNode._id);
2667 + } else {
2668 + //QH('Term', '');
2669 + files.Stop();
2670 + files = null;
2671 + }
2672 + p13clipboard = p13clipboardFolder = null;
2673 + p13clipboardCut = 0;
2674 + p13updateClipview();
2675 + }
2676 +
2677 + var p13filetree = null;
2678 + var p13targetpath = null;
2679 + var p13filetreelocation = [];
2680 +
2681 + function p13gotFiles(data) {
2682 + setSessionActivity();
2683 + //console.log('p13gotFiles', data);
2684 + if ((data.length > 0) && (data.charCodeAt(0) != 123)) { p13gotDownloadBinaryData(data); return; }
2685 + //console.log('p13gotFiles', data);
2686 + data = JSON.parse(decode_utf8(data));
2687 + if (data.action == 'download') { p13gotDownloadCommand(data); return; }
2688 + data.path = data.path.replace(/\//g, "\\");
2689 + if ((p13filetree != null) && (data.path == p13filetree.path)) {
2690 + // This is an update to the same folder
2691 + var checkedNames = p13getCheckedNames();
2692 + p13filetree = data;
2693 + p13updateFiles(checkedNames);
2694 + } else {
2695 + // Make both paths use the same seperator not start with /
2696 + var x1 = data.path.replace(/\//g, "\\"), x2 = p13targetpath.replace(/\//g, "\\");
2697 + while ((x1.length > 0) && (x1[0] == '\\')) { x1 = x1.substring(1); }
2698 + while ((x2.length > 0) && (x2[0] == '\\')) { x2 = x2.substring(1); }
2699 + if ((x1 == x2) || ((data.path == '\\') && (p13targetpath == ''))) {
2700 + // This is a different folder
2701 + p13filetree = data;
2702 + p13updateFiles();
2703 + }
2704 + }
2705 + }
2706 +
2707 + function p13getCheckedNames() {
2708 + // Save all existing checked boxes
2709 + var checkedNames = [], checkboxes = document.getElementsByName('fd');
2710 + for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedNames.push(p13filetree.dir[checkboxes[i].value].n) }; }
2711 + return checkedNames;
2712 + }
2713 +
2714 + function p13updateFiles(checkedNames) {
2715 + var html1 = '', html2 = '', displayPath = '<a style=cursor:pointer onclick=p13folderup(0)>' + "Root" + '</a>', fullPath = 'Root';
2716 +
2717 + // Work on parsing the file path
2718 + var x = p13filetree.path.split('\\');
2719 + p13filetreelocation = [];
2720 + for (var i in x) { if (x[i] != '') { p13filetreelocation.push(x[i]); } } // Remove empty spaces
2721 + for (var i in p13filetreelocation) { displayPath += ' / <a style=cursor:pointer onclick=p13folderup(' + (parseInt(i) + 1) + ')>' + p13filetreelocation[i] + '</a>' } // Setup the path we display
2722 + var newlinkpath = p13filetreelocation.join('/');
2723 +
2724 + // Sort the files
2725 + var filetreexx = p13sort_files(p13filetree.dir);
2726 +
2727 + // Display all files and folders at this location
2728 + for (var i in filetreexx) {
2729 + // Figure out the name and shortname
2730 + var f = filetreexx[i], name = f.n, shortname;
2731 + shortname = name;
2732 + if (name.length > 70) { shortname = EscapeHtml(name.substring(0, 70)) + "..."; } else { shortname = EscapeHtml(name); }
2733 + name = EscapeHtml(name);
2734 +
2735 + // Figure out the size
2736 + var fsize = '';
2737 + if (f.s != null) { fsize = getFileSizeStr(f.s); }
2738 +
2739 + var h = '';
2740 + if (f.t < 3) {
2741 + var right = '';
2742 + h = '<div class=filelist file=999><input file=999 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'>&nbsp;<span style=float:right>' + right + '</span><span><div class=fileIcon' + f.t + '></div><a style=cursor:pointer onclick=p13folderset(\"' + encodeURIComponent(f.nx) + '\")>' + shortname + '</a></span></div>';
2743 + } else {
2744 + var link = shortname;
2745 + if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" style=cursor:pointer onclick=\"p13downloadfile(\'' + encodeURIComponent(newlinkpath + '/' + name) + '\',\'' + encodeURIComponent(name) + '\',' + f.s + ')\">' + shortname + '</a>'; }
2746 + h = '<div class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'>&nbsp;<span style=float:right;padding-right:4px>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
2747 + }
2748 +
2749 + if (f.t < 3) { html1 += h; } else { html2 += h; }
2750 + }
2751 +
2752 + // Display the files and path
2753 + QH('p13files', html1 + html2);
2754 + QH('p13currentpath', displayPath);
2755 + QE('p13FolderUp', p13filetreelocation.length != 0);
2756 +
2757 + // Re-check all boxes if needed using names
2758 + if (checkedNames != null) { var checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkedNames.indexOf(p13filetree.dir[checkboxes[i].value].n) >= 0) { checkboxes[i].checked = true; } } }
2759 +
2760 + // Update the actions buttons
2761 + p13setActions();
2762 + }
2763 +
2764 + function p13folderset(x) {
2765 + p13targetpath = joinPaths(p13filetree.path, p13filetree.dir[x].n).split('\\').join('/');
2766 + files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
2767 + }
2768 +
2769 + function p13folderup(x) {
2770 + if (x == null) { p13filetreelocation.pop(); } else { while (p13filetreelocation.length > x) { p13filetreelocation.pop(); } }
2771 + p13targetpath = p13filetreelocation.join('/');
2772 + files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
2773 + }
2774 +
2775 + var p13sortorder;
2776 + function p13sort_filename(a, b) { if (a.ln > b.ln) return (1 * p13sortorder); if (a.ln < b.ln) return (-1 * p13sortorder); return 0; }
2777 + function p13sort_timestamp(a, b) { if (a.d > b.d) return (1 * p13sortorder); if (a.d < b.d) return (-1 * p13sortorder); return 0; }
2778 + function p13sort_bysize(a, b) { if (a.s == b.s) return p13sort_filename(a, b); return (((a.s - b.s)) * p13sortorder); }
2779 +
2780 + function p13sort_files(files) {
2781 + var r = [], sortselection = Q('p13sortdropdown').value;
2782 + for (var i in files) { files[i].nx = i; if (files[i].s == null) { files[i].s = 0; } if (files[i].n == null) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
2783 + p13sortorder = 1;
2784 + if (sortselection > 3) { p13sortorder = -1; sortselection -= 3; }
2785 + if (sortselection == 1) { r.sort(p13sort_filename); }
2786 + else if (sortselection == 2) { r.sort(p13sort_bysize); }
2787 + else if (sortselection == 3) { r.sort(p13sort_timestamp); }
2788 + return r;
2789 + }
2790 +
2791 + function p13setActions() {
2792 + if (p13filetree == null) {
2793 + QE('p13DeleteFileButton', false);
2794 + QE('p13NewFolderButton', false);
2795 + QE('p13UploadButton', false);
2796 + QE('p13RenameFileButton', false);
2797 + QE('p13SelectAllButton', false);
2798 + Q('p13SelectAllButton').value = "Tout";
2799 + QE('p13RefreshButton', false);
2800 + QE('p13CutButton', false);
2801 + QE('p13CopyButton', false);
2802 + QE('p13PasteButton', false);
2803 + } else {
2804 + var cc = p13getFileSelCount(), tc = p13getFileCount(), sfc = p13getFileSelCount(false); // In order: number of entires selected, number of total entries, number of selected entires that are files (not folders)
2805 + var winAgent = ((currentNode.agent.id > 0) && (currentNode.agent.id < 5));
2806 + QE('p13DeleteFileButton', (cc > 0) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2807 + QE('p13NewFolderButton', ((p13filetreelocation.length > 0) || (winAgent == false)));
2808 + QE('p13UploadButton', ((p13filetreelocation.length > 0) || (winAgent == false)));
2809 + QE('p13RenameFileButton', (cc == 1) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2810 + QE('p13SelectAllButton', tc > 0);
2811 + Q('p13SelectAllButton').value = (cc > 0 ? "None" : "Tout");
2812 + QE('p13RefreshButton', true);
2813 + QE('p13CutButton', (cc > 0) && (cc == sfc) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2814 + QE('p13CopyButton', (cc > 0) && (cc == sfc) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2815 + QE('p13PasteButton', ((p13filetreelocation.length > 0) || (winAgent == false)) && ((p13clipboard != null) && (p13clipboard.length > 0)));
2816 + }
2817 + }
2818 +
2819 + function p13getFileSelCount(includeDirs) { var cc = 0; var checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == '3'))) cc++; } return cc; }
2820 + function p13getFileSelDirCount() { var cc = 0, checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '999')) cc++; } return cc; }
2821 + function p13getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fd'); return checkboxes.length; }
2822 + function p13selectallfile() { var nv = (p13getFileSelCount() == 0), checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p13setActions(); }
2823 + function p13createfolder() { setDialogMode(2, "New Folder", 3, p13createfolderEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% />'); focusTextBox('p13renameinput'); p13fileNameCheck(); }
2824 + function p13createfolderEx() { files.sendText({ action: 'mkdir', reqid: 1, path: p13filetreelocation.join('/') + '/' + Q('p13renameinput').value }); p13folderup(999); }
2825 + function p13deletefile() { var cc = p13getFileSelCount(), rec = (p13getFileSelDirCount() > 0) ? '<br /><br /><label><input type=checkbox id=p13recdeleteinput>' + "Recursive delete" + '</label><br>' : "<input type=checkbox id=p13recdeleteinput style='display:none'>"; setDialogMode(2, "Delete", 3, p13deletefileEx, (cc > 1) ? (format("Delete {0} selected items?", cc) + rec) : ("Delete selected item?" + rec)); }
2826 + function p13deletefileEx() { var delfiles = [], checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { delfiles.push(p13filetree.dir[checkboxes[i].value].n); } } files.sendText({ action: 'rm', reqid: 1, path: p13filetreelocation.join('/'), delfiles: delfiles, rec: Q('p13recdeleteinput').checked }); p13folderup(999); }
2827 + function p13renamefile() { var renamefile, checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { renamefile = p13filetree.dir[checkboxes[i].value].n; } } setDialogMode(2, "Rename", 3, p13renamefileEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% value="' + renamefile + '" />', { action: 'rename', path: p13filetreelocation.join('/'), oldname: renamefile }); focusTextBox('p13renameinput'); p13fileNameCheck(); }
2828 + function p13renamefileEx(b, t) { t.newname = Q('p13renameinput').value; files.sendText(t); p13folderup(999); }
2829 + function p13fileNameCheck(e) { var x = isFilenameValid(Q('p13renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); } }
2830 + function p13uploadFile() { setDialogMode(2, "Upload File", 3, p13uploadFileEx, '<input type=file name=files id=p13uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p13uploadinput\')" />'); updateUploadDialogOk('p13uploadinput'); }
2831 + function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); }
2832 + function p13viewfile() {
2833 + var checkboxes = document.getElementsByName('fd');
2834 + for (var i = 0; i < checkboxes.length; i++) {
2835 + if (checkboxes[i].checked) {
2836 + if (p13filetree.dir[checkboxes[i].value].s <= 204800) {
2837 + p13downloadfile(encodeURIComponent(p13filetreelocation.join('/') + '/' + p13filetree.dir[checkboxes[i].value].n), encodeURIComponent(p13filetree.dir[checkboxes[i].value].n), p13filetree.dir[checkboxes[i].value].s, 'viewer');
2838 + } else { messagebox("File Editor", "Only files less than 200k can be edited."); }
2839 + break;
2840 + }
2841 + }
2842 + }
2843 +
2844 + var p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0;
2845 + function p13copyFile(cut) { var checkboxes = document.getElementsByName('fd'); p13clipboard = []; p13clipboardCut = cut, p13clipboardFolder = p13targetpath; for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p13clipboard.push(p13filetree.dir[checkboxes[i].value].n); } } p13updateClipview(); }
2846 + function p13pasteFile() {
2847 + var x = '';
2848 + if ((p13clipboard != null) && (p13clipboard.length > 0)) {
2849 + if (p13clipboardCut == 0) {
2850 + if (p13clipboard.length > 1) { x = format("Confirm copy of {0} entries's to this location?", p13clipboard.length); } else { x = format("Confirm copy of 1 entrie to this location?"); }
2851 + } else {
2852 + if (p13clipboard.length > 1) { x = format("Confirm move of {0} entries's to this location?", p13clipboard.length); } else { x = format("Confirm move of 1 entrie to this location?"); }
2853 + }
2854 + }
2855 + setDialogMode(2, "Paste", 3, p13pasteFileEx, x);
2856 + }
2857 + function p13pasteFileEx() { files.sendText({ action: (p13clipboardCut == 0 ? 'copy' : 'move'), reqid: 1, scpath: p13clipboardFolder, dspath: p13targetpath, names: p13clipboard }); p13folderup(999); if (p13clipboardCut == 1) { p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0; p13updateClipview(); } }
2858 + function p13updateClipview() {
2859 + var x = '';
2860 + if ((p13clipboard != null) && (p13clipboard.length > 0)) {
2861 + if (p13clipboardCut == 0) {
2862 + if (p13clipboard.length > 1) {
2863 + x = format("Holding {0} entries for copy" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "Clear" + '</a>.', p13clipboard.length);
2864 + } else {
2865 + x = format("Holding 1 entrie for copy" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "Clear" + '</a>.');
2866 + }
2867 + } else {
2868 + if (p13clipboard.length > 1) {
2869 + x = format("Holding {0} entries for move" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "Clear" + '</a>.', p13clipboard.length);
2870 + } else {
2871 + x = format("Holding 1 entrie for move" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "Clear" + '</a>.');
2872 + }
2873 + }
2874 + }
2875 + QH('p13bottomstatus', x);
2876 + p13setActions();
2877 + }
2878 + function p13clearClip() { p13clipboard = null; p13clipboardFolder = null; p13clipboardCut = 0; p13updateClipview(); return false; } function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
2879 + function getFileSelCount(includeDirs) { var cc = 0; var checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == "3"))) cc++; } return cc; }
2880 + function getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fc'); return checkboxes.length; }
2881 +
2882 + //
2883 + // FILES DOWNLOAD
2884 + //
2885 +
2886 + var downloadFile; // Global state for file download
2887 +
2888 + // Called by the html page to start a download, arguments are: path, file name and file size.
2889 + function p13downloadfile(x, y, z) {
2890 + if (xxdialogMode || downloadFile || !files) return;
2891 + downloadFile = { path: decodeURIComponent(x), file: decodeURIComponent(y), size: z, tsize: 0, data: '', state: 0, id: Math.random() }
2892 + //console.log('p13downloadFileCancel', downloadFile);
2893 + files.sendText({ action: 'download', sub: 'start', id: downloadFile.id, path: downloadFile.path });
2894 + setDialogMode(2, "Download File", 10, p13downloadFileCancel, '<div>' + downloadFile.file + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
2895 + }
2896 +
2897 + // Called by the html page to cancel the download
2898 + function p13downloadFileCancel() { setDialogMode(0); files.sendText({ action: 'download', sub: 'cancel', id: downloadFile.id }); downloadFile = null; }
2899 +
2900 + // Called by the transport when download control command is received
2901 + function p13gotDownloadCommand(cmd) {
2902 + //console.log('p13gotDownloadCommand', cmd);
2903 + if ((downloadFile == null) || (cmd.id != downloadFile.id)) return;
2904 + if (cmd.sub == 'start') { downloadFile.state = 1; files.sendText({ action: 'download', sub: 'startack', id: downloadFile.id }); }
2905 + else if (cmd.sub == 'cancel') { downloadFile = null; setDialogMode(0); }
2906 + }
2907 +
2908 + // Called by the transport when binary data is received
2909 + function p13gotDownloadBinaryData(data) {
2910 + if (!downloadFile || downloadFile.state == 0) return;
2911 + if (data.length > 4) {
2912 + downloadFile.tsize += (data.length - 4); // Add to the total bytes received
2913 + downloadFile.data += data.substring(4); // Append the data
2914 + Q('d2progressBar').value = downloadFile.tsize; // Change the progress bar
2915 + }
2916 + if ((ReadInt(data, 0) & 1) != 0) { // Check end flag
2917 + saveAs(data2blob(downloadFile.data), downloadFile.file); downloadFile = null; setDialogMode(0); // Save the file
2918 + } else {
2919 + files.sendText({ action: 'download', sub: 'ack', id: downloadFile.id }); // Send the ACK
2920 + }
2921 + }
2922 +
2923 + /*
2924 + var downloadFile; // Global state for file download
2925 +
2926 + // Called by the html page to start a download, arguments are: path, file name and file size.
2927 + function p13downloadfile(x, y, z) {
2928 + if (xxdialogMode) return;
2929 + downloadFile = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotDownloadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl); // Create our websocket file transport
2930 + downloadFile.ctrlMsgAllowed = false;
2931 + downloadFile.onStateChanged = onFileDownloadStateChange;
2932 + downloadFile.xpath = decodeURIComponent(x);
2933 + downloadFile.xfile = decodeURIComponent(y);
2934 + downloadFile.xsize = z;
2935 + downloadFile.xtsize = 0;
2936 + downloadFile.xstate = 0;
2937 + downloadFile.Start(filesNode._id);
2938 + setDialogMode(2, "Download File", 10, p13downloadFileCancel, '<div>' + downloadFile.xfile + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
2939 + }
2940 +
2941 + // Called by the html page to cancel the download
2942 + function p13downloadFileCancel(button, tag) {
2943 + //console.log('p13downloadFileCancel');
2944 + downloadFile.Stop();
2945 + delete downloadFile;
2946 + downloadFile = null;
2947 + }
2948 +
2949 + // Called by the file transport to indicate when the transport connection state has changed
2950 + function onFileDownloadStateChange(xdownloadFile, state) {
2951 + switch (state) {
2952 + case 0: // Transport as disconnected. If this is not part of an abort, we need to save the file
2953 + setDialogMode(0); // Close any dialog boxes if present
2954 + if ((downloadFile != null) && (downloadFile.xstate == 1)) { saveAs(data2blob(downloadFile.xdata), downloadFile.xfile); } // Save the file
2955 + break;
2956 + case 3: // Transport as connected, send a command to indicate we want to start a file download
2957 + downloadFile.send(JSON.stringify({ action: 'download', reqid: 1, path: downloadFile.xpath }));
2958 + break;
2959 + default:
2960 + console.log('Unknown onFileDownloadStateChange state', state);
2961 + break;
2962 + }
2963 + }
2964 +
2965 + // Called by the transport when data is received
2966 + function p13gotDownloadData(data) {
2967 + if (downloadFile.xstate == 0) { // If state is 0, this is a command confirming if the file will be transfered.
2968 + var cmd = JSON.parse(data);
2969 + if (cmd.action == 'downloadstart') { // Yes, the file is about to start
2970 + downloadFile.xstate = 1; // Switch to state 1, we will start receiving the file data
2971 + downloadFile.xdata = ''; // Start with empty data
2972 + downloadFile.send('a'); // Send the first ACK
2973 + } else if (cmd.action == 'downloaderror') { // Problem opening this file, cancel
2974 + p13downloadFileCancel();
2975 + }
2976 + } else { // We are in the process of receiving the file
2977 + downloadFile.xtsize += (data.length); // Add to the total bytes received
2978 + downloadFile.xdata += data; // Append the data
2979 + Q('d2progressBar').value = downloadFile.xtsize; // Change the progress bar
2980 + downloadFile.send('a'); // Send the ACK
2981 + }
2982 + }
2983 + */
2984 +
2985 + //
2986 + // FILES UPLOAD
2987 + //
2988 +
2989 + var uploadFile;
2990 + function p13doUploadFiles(files) {
2991 + if (xxdialogMode) return;
2992 + uploadFile = {};
2993 + uploadFile.xpath = p13filetreelocation.join('/');
2994 + uploadFile.xfiles = files;
2995 + uploadFile.xfilePtr = -1;
2996 + setDialogMode(2, "Upload File", 10, p13uploadFileCancel, '<div id=p13dfileName>' + "Connecting..." + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=0 />');
2997 + p13uploadReconnect();
2998 + }
2999 +
3000 + function onFileUploadStateChange(xdownloadFile, state) {
3001 + switch (state) {
3002 + case 0:
3003 + p13folderup(9999);
3004 + break;
3005 + case 3:
3006 + p13uploadNextFile();
3007 + break;
3008 + default:
3009 + console.log('Unknown onFileUploadStateChange state', state);
3010 + break;
3011 + }
3012 + }
3013 +
3014 + // Connect again
3015 + function p13uploadReconnect() {
3016 + uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
3017 + uploadFile.ws.attemptWebRTC = false;
3018 + uploadFile.ws.ctrlMsgAllowed = false;
3019 + uploadFile.ws.onStateChanged = onFileUploadStateChange;
3020 + uploadFile.ws.Start(filesNode._id);
3021 + }
3022 +
3023 + // Push the next file
3024 + function p13uploadNextFile() {
3025 + uploadFile.xfilePtr++;
3026 + if (uploadFile.xfiles.length > uploadFile.xfilePtr) {
3027 + uploadFile.xptr = 0;
3028 + var file = uploadFile.xfiles[uploadFile.xfilePtr];
3029 + QH('p13dfileName', file.name);
3030 + Q('d2progressBar').max = file.size;
3031 + Q('d2progressBar').value = 0;
3032 +
3033 + uploadFile.xreader = new FileReader();
3034 + uploadFile.xreader.onload = function () {
3035 + uploadFile.xdata = uploadFile.xreader.result;
3036 + uploadFile.ws.sendText({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength });
3037 + };
3038 + uploadFile.xreader.readAsArrayBuffer(file);
3039 + } else {
3040 + p13uploadFileCancel();
3041 + }
3042 + }
3043 +
3044 + // Used to cancel the entire transfer.
3045 + function p13uploadFileCancel(button, tag) {
3046 + if (uploadFile != null) {
3047 + if (uploadFile.ws != null) {
3048 + uploadFile.ws.Stop();
3049 + uploadFile.ws = null;
3050 + }
3051 + uploadFile = null;
3052 + }
3053 + setDialogMode(0); // Close any dialog boxes if present
3054 + }
3055 +
3056 + // Receive upload ack from the mesh agent, use this to keep sending more data
3057 + function p13gotUploadData(data) {
3058 + var cmd = JSON.parse(data);
3059 + if ((uploadFile == null) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
3060 +
3061 + if (cmd.action == 'uploadstart') {
3062 + p13uploadNextPart(false);
3063 + for (var i = 0; i < 8; i++) { p13uploadNextPart(true); } // Send 8 more blocks of 4 k to full the websocket.
3064 + } else if (cmd.action == 'uploadack') {
3065 + p13uploadNextPart(false);
3066 + } else if (cmd.action == 'uploaderror') {
3067 + p13uploadFileCancel();
3068 + }
3069 + }
3070 +
3071 + // Push the next part of the file into the websocket. If dataPriming is true, push more data only if it's not the last block of the file.
3072 + function p13uploadNextPart(dataPriming) {
3073 + var data = uploadFile.xdata;
3074 + var start = uploadFile.xptr;
3075 + var end = uploadFile.xptr + 4096;
3076 + if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
3077 + if (start == data.byteLength) {
3078 + if (uploadFile.ws != null) { uploadFile.ws.Stop(); uploadFile.ws = null; }
3079 + if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadReconnect(); } else { p13uploadFileCancel(); }
3080 + } else {
3081 + var datapart = data.slice(start, end);
3082 + uploadFile.ws.send(datapart);
3083 + uploadFile.xptr = end;
3084 + Q('d2progressBar').value = end;
3085 + }
3086 + }
3087 +
3088 + //
3089 + // MY MESHS
3090 + //
3091 +
3092 + var currentMesh;
3093 + function p20updateMesh() {
3094 + if (currentMesh == null) return;
3095 + QH('p20meshName', EscapeHtml(currentMesh.name));
3096 + var meshtype = format(" #{0} Inconnue", currentMesh.mtype);
3097 + var meshrights = currentMesh.links[userinfo._id].rights;
3098 + if (currentMesh.mtype == 1) meshtype = "Intel&reg; AMT only, no agent";
3099 + if (currentMesh.mtype == 2) meshtype = "Managed using a software agent";
3100 +
3101 + var x = '';
3102 + x += addHtmlValue("Name", addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0));
3103 + x += addHtmlValue("Description", addLinkConditional(((currentMesh.desc && currentMesh.desc != '') ? EscapeHtml(currentMesh.desc) : ('<i>' + "None" + '</i>')), 'p20editmesh(2)', (meshrights & 1) != 0));
3104 + x += addHtmlValue("Type", meshtype);
3105 + //x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
3106 +
3107 + //x += '<br><input type=button value=Notes onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
3108 +
3109 + x += '<br style=clear:both><br>';
3110 + var currentMeshLinks = currentMesh.links[userinfo._id];
3111 + if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += '<div style=margin-bottom:6px><a onclick=p20showAddMeshUserDialog() style=cursor:pointer><img src=images/icon-addnew.png border=0 height=12 width=12>' + "Ajouter un utilisateur" + '</a></div>'; }
3112 +
3113 + /*
3114 + if ((meshrights & 4) != 0) {
3115 + if (currentMesh.mtype == 1) {
3116 + x += '<a onclick=addCiraDeviceToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px><img src=images/icon-installmesh.png border=0 height=12 width=12> Install CIRA</a>';
3117 + x += '<a onclick=addDeviceToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px><img src=images/icon-installmesh.png border=0 height=12 width=12> Install local</a>';
3118 + }
3119 + if (currentMesh.mtype == 2) {
3120 + x += '<a onclick=addAgentToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> Install</a>';
3121 + }
3122 + }
3123 + */
3124 +
3125 + /*
3126 + function getMeshActions(mesh, meshrights) {
3127 + if ((meshrights & 4) == 0) return '';
3128 + var r = '';
3129 + if (mesh.mtype == 1) {
3130 + r += ' <a style=cursor:pointer;font-size:10px onclick=addCiraDeviceToMesh(\"' + mesh._id + '\")>Add CIRA</a>';
3131 + r += ' <a style=cursor:pointer;font-size:10px onclick=addDeviceToMesh(\"' + mesh._id + '\")>Add Local</a>';
3132 + }
3133 + if (mesh.mtype == 2) {
3134 + r += ' <a style=cursor:pointer;font-size:10px onclick=addAgentToMesh(\"' + mesh._id + '\")>Add Agent</a>';
3135 + }
3136 + return r;
3137 + }
3138 + */
3139 +
3140 + x += '<table style="color:black;background-color:#EEE;border-color:#AAA;border-width:1px;border-style:solid;border-collapse:collapse" border=0 cellpadding=2 cellspacing=0 width=100%><tbody><tr style=background-color:#AAAAAA;font-weight:bold><th scope=col style=text-align:left;width:430px>' + "User Authorizations" + '</th></tr>';
3141 +
3142 + // Sort the users for this mesh
3143 + var count = 1, sortedusers = [];
3144 + for (var i in currentMesh.links) { sortedusers.push({ id: i, name: i.split('/')[2], rights: currentMesh.links[i].rights }); }
3145 + sortedusers.sort(function (a, b) { if (a.name > b.name) return 1; if (a.name < b.name) return -1; return 0; });
3146 +
3147 + // Display all users for this mesh
3148 + for (var i in sortedusers) {
3149 + var trash = '', rights = "Partial Rights", r = sortedusers[i].rights;
3150 + if (r == 0xFFFFFFFF) rights = "Full Administrator"; else if (r == 0) rights = "No Rights";
3151 + if ((i != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = '<a onclick=p20deleteUser(event,"' + encodeURIComponent(sortedusers[i].id) + '") style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
3152 + x += '<tr onclick=p20viewuser("' + encodeURIComponent(sortedusers[i].id) + '") style=height:32px;cursor:pointer' + (((count % 2) == 0) ? ';background-color:#DDD' : '') + '><td>';
3153 + x += '<div style=float:right>' + trash + '</div><div style=float:right;padding-right:4px>' + rights + '</div><div class=m2></div><div>&nbsp;' + EscapeHtml(decodeURIComponent(sortedusers[i].name)) + '<div></div></div>';
3154 + x += '</td></tr>';
3155 + ++count;
3156 + }
3157 +
3158 + x += '</tbody></table>';
3159 +
3160 + // If we are full administrator on this mesh, allow deletion of the mesh
3161 + if (meshrights == 0xFFFFFFFF) { x += '<div style=font-size:small;text-align:right;margin-top:6px><span><a onclick=p20showDeleteMeshDialog() style=cursor:pointer>' + "Delete Group" + '</a></span></div>'; }
3162 +
3163 + QH('p20info', x);
3164 + }
3165 +
3166 + function p20showDeleteMeshDialog() {
3167 + if (xxdialogMode) return false;
3168 + var x = format("Êtes-vous sûr de vouloir supprimer le groupe {0}? La suppression du groupe de périphériques supprimera également toutes les informations relatives aux périphériques de ce groupe.", EscapeHtml(currentMesh.name)) + '<br /><br />';
3169 + x += '<label><input id=p20check type=checkbox onchange=p20validateDeleteMeshDialog() />' + "Confirm" + '</label>';
3170 + setDialogMode(2, "Delete Group", 3, p20showDeleteMeshDialogEx, x);
3171 + p20validateDeleteMeshDialog();
3172 + return false;
3173 + }
3174 +
3175 + function p20validateDeleteMeshDialog() {
3176 + QE('idx_dlgOkButton', Q('p20check').checked);
3177 + }
3178 +
3179 + function p20showDeleteMeshDialogEx(buttons, tag) {
3180 + meshserver.send({ action: 'deletemesh', meshid: currentMesh._id, meshname: currentMesh.name });
3181 + }
3182 +
3183 + function p20editmesh(focus) {
3184 + if (xxdialogMode) return;
3185 + var x = addHtmlValue("Name", '<input id=dp20meshname style=width:170px maxlength=32 onchange=p20editmeshValidate() onkeyup=p20editmeshValidate() />');
3186 + x += addHtmlValue("Description", '<input id=dp20meshdesc style=width:170px maxlength=1024 onkeyup=p20editmeshValidate() />');
3187 + setDialogMode(2, "Edit Device Group", 3, p20editmeshEx, x);
3188 + Q('dp20meshname').value = currentMesh.name;
3189 + if (currentMesh.desc) Q('dp20meshdesc').value = currentMesh.desc;
3190 + p20editmeshValidate();
3191 + if (focus == 2) { Q('dp20meshdesc').focus(); } else { Q('dp20meshname').focus(); }
3192 + }
3193 +
3194 + function p20editmeshEx() {
3195 + meshserver.send({ action: 'editmesh', meshid: currentMesh._id, meshname: Q('dp20meshname').value, desc: Q('dp20meshdesc').value });
3196 + }
3197 +
3198 + function p20editmeshValidate() {
3199 + QE('idx_dlgOkButton', Q('dp20meshname').value.length > 0);
3200 + }
3201 +
3202 + function p20showAddMeshUserDialog() {
3203 + if (xxdialogMode) return;
3204 + var x = addHtmlValue('User', '<input id=dp20username style=width:170px maxlength=32 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() />');
3205 + x += '<div style="border:2px groove gray;background-color:white;max-height:120px;overflow-y:scroll">';
3206 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20fulladmin>' + "Full Administrator" + '</label><br>';
3207 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editmesh>' + "Edit Device Group" + '</label><br>';
3208 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20manageusers>' + "Manage Device Group Users" + '</label><br>';
3209 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20managecomputers>' + "Manage Device Group Computers" + '</label><br>';
3210 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotecontrol>' + "Remote Control" + '</label><br>';
3211 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remoteview style=margin-left:12px>' + "Remote View Only" + '</label><br>';
3212 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotelimitedinput style=margin-left:12px>' + "Limited Input Only" + '</label><br>';
3213 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noterminal style=margin-left:12px>' + "No Terminal Access" + '</label><br>';
3214 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20nofiles style=margin-left:12px>' + "No File Access" + '</label><br>';
3215 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noamt style=margin-left:12px>' + "No Intel&reg; AMT" + '</label><br>';
3216 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshagentconsole>' + "Mesh Agent Console" + '</label><br>';
3217 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshserverfiles>' + "Server Files" + '</label><br>';
3218 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>' + "Wake Devices" + '</label><br>';
3219 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>' + "Edit Device Notes" + '</label><br>';
3220 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20limitevents>' + "Show Only Own Events" + '</label><br>';
3221 + x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20chatnotify>' + "Chat & Notify" + '</label><br>';
3222 + x += '</div>';
3223 + setDialogMode(2, "Ajouter un utilisateur au groupe", 3, p20showAddMeshUserDialogEx, x);
3224 + p20validateAddMeshUserDialog();
3225 + Q('dp20username').focus();
3226 + }
3227 +
3228 + function p20validateAddMeshUserDialog() {
3229 + var meshrights = currentMesh.links[userinfo._id].rights;
3230 + QE('idx_dlgOkButton', (Q('dp20username').value.length > 0));
3231 + QE('p20fulladmin', meshrights == 0xFFFFFFFF);
3232 + QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF));
3233 + QE('p20manageusers', !Q('p20fulladmin').checked);
3234 + QE('p20managecomputers', !Q('p20fulladmin').checked);
3235 + QE('p20remotecontrol', !Q('p20fulladmin').checked);
3236 + QE('p20meshagentconsole', !Q('p20fulladmin').checked);
3237 + QE('p20meshserverfiles', !Q('p20fulladmin').checked);
3238 + QE('p20wakedevices', !Q('p20fulladmin').checked);
3239 + QE('p20editnotes', !Q('p20fulladmin').checked);
3240 + QE('p20remoteview', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
3241 + QE('p20noterminal', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
3242 + QE('p20nofiles', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
3243 + QE('p20noamt', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
3244 + }
3245 +
3246 + function p20showAddMeshUserDialogEx() {
3247 + var meshadmin = 0;
3248 + if (Q('p20fulladmin').checked == true) { meshadmin = 0xFFFFFFFF; } else {
3249 + if (Q('p20editmesh').checked == true) meshadmin += 1;
3250 + if (Q('p20manageusers').checked == true) meshadmin += 2;
3251 + if (Q('p20managecomputers').checked == true) meshadmin += 4;
3252 + if (Q('p20remotecontrol').checked == true) meshadmin += 8;
3253 + if (Q('p20meshagentconsole').checked == true) meshadmin += 16;
3254 + if (Q('p20meshserverfiles').checked == true) meshadmin += 32;
3255 + if (Q('p20wakedevices').checked == true) meshadmin += 64;
3256 + if (Q('p20editnotes').checked == true) meshadmin += 128;
3257 + if (Q('p20remoteview').checked == true) meshadmin += 256;
3258 + if (Q('p20noterminal').checked == true) meshadmin += 512;
3259 + if (Q('p20nofiles').checked == true) meshadmin += 1024;
3260 + if (Q('p20noamt').checked == true) meshadmin += 2048;
3261 + }
3262 + meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value, meshadmin: meshadmin });
3263 + }
3264 +
3265 + function p20viewuser(userid) {
3266 + if (xxdialogMode) return;
3267 + userid = decodeURIComponent(userid);
3268 + var r = [], cmeshrights = currentMesh.links[userinfo._id].rights, meshrights = currentMesh.links[userid].rights;
3269 + if (meshrights == 0xFFFFFFFF) r.push("Full Administrator"); else {
3270 + if ((meshrights & 1) != 0) r.push("Edit Device Group");
3271 + if ((meshrights & 2) != 0) r.push("Manage Device Group Users");
3272 + if ((meshrights & 4) != 0) r.push("Manage Device Group Computers");
3273 + if ((meshrights & 8) != 0) r.push("Remote Control");
3274 + if ((meshrights & 16) != 0) r.push("Agent Console");
3275 + if ((meshrights & 32) != 0) r.push("Server Files");
3276 + if ((meshrights & 64) != 0) r.push("Wake Devices");
3277 + if ((meshrights & 128) != 0) r.push("Edit Notes");
3278 + if ((meshrights & 256) != 0) r.push("Remote View Only");
3279 + if ((meshrights & 512) != 0) r.push("No Terminal");
3280 + if ((meshrights & 1024) != 0) r.push("No Files");
3281 + if ((meshrights & 2048) != 0) r.push("No Intel&reg; AMT");
3282 + if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r.push("Limited Input");
3283 + if ((meshrights & 8192) != 0) r.push("Self Events Only");
3284 + if ((meshrights & 16384) != 0) r.push("Chat & Notify");
3285 + }
3286 + if (r.length == 0) { r.push("No Rights"); }
3287 + var buttons = 1, x = addHtmlValue("User", EscapeHtml(decodeURIComponent(userid.split('/')[2])));
3288 + x += addHtmlValue("Permissions", r.join(", "));
3289 + if (((userinfo._id) != userid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) buttons += 4;
3290 + setDialogMode(2, "Device Group User", buttons, p20viewuserEx, x, userid);
3291 + }
3292 +
3293 + function p20viewuserEx(button, userid) { if (button != 2) return; setDialogMode(2, "Remote Mesh User", 3, p20viewuserEx2, format("Confirm removal of user {0}?", userid.split('/')[2]), userid); }
3294 + function p20deleteUser(e, userid) { haltEvent(e); p20viewuserEx(2, decodeURIComponent(userid)); }
3295 + function p20viewuserEx2(button, userid) { meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid }); }
3296 +
3297 + //
3298 + // PANELS
3299 + //
3300 +
3301 + var xxcurrentView = -1;
3302 + function go(x) {
3303 + setSessionActivity();
3304 + if (xxdialogMode || xxcurrentView == x) return;
3305 + updateFooterMenu();
3306 + setDialogMode(0);
3307 + // Edit this line when adding a new screen
3308 + for (var i = 0; i < 32; i++) { QV('p' + i, i == x); }
3309 + xxcurrentView = x;
3310 + }
3311 +
3312 + //
3313 + // POPUP DIALOG
3314 + //
3315 +
3316 + // undefined = Hidden, 1 = Generic Message
3317 + var xxdialogMode;
3318 + var xxdialogFunc;
3319 + var xxdialogButtons;
3320 + var xxdialogTag;
3321 +
3322 + // Display a dialog box
3323 + // Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
3324 + function setDialogMode(x, y, b, f, c, tag) {
3325 + setSessionActivity();
3326 + xxdialogMode = x;
3327 + xxdialogFunc = f;
3328 + xxdialogButtons = b;
3329 + xxdialogTag = tag;
3330 + QE('idx_dlgOkButton', true);
3331 + QV('idx_dlgOkButton', b & 1);
3332 + QV('idx_dlgCancelButton', b & 2);
3333 + QV('id_dialogclose', (b & 2) || (b & 8));
3334 + QV('idx_dlgButtonBar', b & 7);
3335 + if (y) QH('id_dialogtitle', y);
3336 + for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
3337 + QV('dialog', x);
3338 + if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
3339 + }
3340 +
3341 + function dialogclose(x) {
3342 + setSessionActivity();
3343 + var f = xxdialogFunc;
3344 + var b = xxdialogButtons;
3345 + var t = xxdialogTag;
3346 + setDialogMode();
3347 + if (((b & 8) || x) && f) f(x, t);
3348 + }
3349 +
3350 + function putstore(name, val) { try { if ((typeof (localStorage) === 'undefined') || (localStorage.getItem(name) == val)) return; if (val == null) { localStorage.removeItem(name); } else { localStorage.setItem(name, val); } } catch (e) { } if (name[0] != '_') { var s = {}; for (var i = 0, len = localStorage.length; i < len; ++i) { var k = localStorage.key(i); if (k[0] != '_') { s[k] = localStorage.getItem(k); } } meshserver.send({ action: 'userWebState', state: JSON.stringify(s) }); } }
3351 + function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
3352 + function center() { QS('dialog').left = ((((getDocWidth() - 300) / 2)) + 'px'); deskAdjust(); deskAdjust(); /*drawDeviceTimeline();*/ }
3353 + function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
3354 + function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
3355 + function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
3356 + function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
3357 + function haltReturn(e) { if (e.keyCode == 13) { haltEvent(e); } }
3358 + function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); }
3359 + function reload() { window.location.href = window.location.href; }
3360 + function getNodeFromId(id) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } return null; }
3361 + function addHtmlValue(t, v) { return '<table><td style=width:120px>' + t + '<td><b>' + v + '</b></table>'; }
3362 + function addHtmlValue2(t, v) { return '<div><div style=display:inline-block;float:right>' + v + '</div><div style=display:inline-block>' + t + '</div></div>'; }
3363 + function addLink(x, f) { return '<a style=cursor:pointer;color:darkblue;text-decoration:none onclick=\'' + f + '\'>&diams; ' + x + '</a>'; }
3364 + function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
3365 + function passwordcheck(p) { var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()]).{8,}/; return re.test(p); }
3366 + function getFileSizeStr(size) { if (size == 1) return "1 octet"; return format('{0} bytes', size); }
3367 + function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
3368 + function focusTextBox(x) { setTimeout(function () { Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
3369 + var isFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); } })();
3370 + function parseUriArgs() { var name, r = {}, parsedUri = window.document.location.href.split(/[\?&|\=]/); parsedUri.splice(0, 1); for (x in parsedUri) { switch (x % 2) { case 0: { name = decodeURIComponent(parsedUri[x]); break; } case 1: { r[name] = decodeURIComponent(parsedUri[x]); var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } break; } default: { break; } } } return r; }
3371 + function printDate(d) { return d.toLocaleDateString(args.locale); }
3372 + function printTime(d) { return d.toLocaleTimeString(args.locale); }
3373 + function printDateTime(d) { return d.toLocaleString(args.locale); }
3374 + function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
3375 + function nobreak(x) { return x.split(' ').join('&nbsp;'); }
3376 +
3377 + </script>
3378 +
3379 +</body></html>
\ No newline at end of file
views/translations/default_fr.handlebars new
+9308
@@ -0,0 +1,9308 @@
1 +<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
2 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
3 + <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
4 + <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
5 + <meta name="apple-mobile-web-app-capable" content="yes">
6 + <meta name="format-detection" content="telephone=no">
7 + <link rel="shortcut icon" type="image/x-icon" href="{{{domainurl}}}favicon.ico">
8 + <link keeplink="1" type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
9 + <link type="text/css" href="styles/ol.css" media="screen" rel="stylesheet" title="CSS">
10 + <link type="text/css" href="styles/ol3-contextmenu.min.css" media="screen" rel="stylesheet" title="CSS">
11 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
12 + <script type="text/javascript" src="scripts/meshcentral.js"></script>
13 + <script type="text/javascript" src="scripts/amt-0.2.0.js"></script>
14 + <script type="text/javascript" src="scripts/amt-wsman-0.2.0.js"></script>
15 + <script type="text/javascript" src="scripts/amt-desktop-0.0.2.js"></script>
16 + <script type="text/javascript" src="scripts/amt-terminal-0.0.2.js"></script>
17 + <script type="text/javascript" src="scripts/zlib.js"></script>
18 + <script type="text/javascript" src="scripts/zlib-inflate.js"></script>
19 + <script type="text/javascript" src="scripts/zlib-adler32.js"></script>
20 + <script type="text/javascript" src="scripts/zlib-crc32.js"></script>
21 + <script type="text/javascript" src="scripts/amt-redir-ws-0.1.0.js"></script>
22 + <script type="text/javascript" src="scripts/amt-wsman-ws-0.2.0.js"></script>
23 + <script type="text/javascript" src="scripts/agent-redir-ws-0.1.1.js"></script>
24 + <script type="text/javascript" src="scripts/agent-redir-rtc-0.1.0.js"></script>
25 + <script type="text/javascript" src="scripts/agent-desktop-0.0.2.js"></script>
26 + <script type="text/javascript" src="scripts/qrcode.min.js"></script>
27 + <script keeplink="1" type="text/javascript" src="scripts/u2f-api.js"></script>
28 + <script keeplink="1" type="text/javascript" src="scripts/charts.js"></script>
29 + <script keeplink="1" type="text/javascript" src="scripts/filesaver.js"></script>
30 + <script keeplink="1" type="text/javascript" src="scripts/ol.js"></script>
31 + <script keeplink="1" type="text/javascript" src="scripts/ol3-contextmenu.js"></script>
32 + <title>{{{title}}}</title>
33 +</head>
34 +<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" oncontextmenu="handleContextMenu(event)" style="display:none;min-width:495px">
35 + <!-- right click menu -->
36 + <div id="contextMenu" class="contextMenu noselect" style="display:none">
37 + <div id="cxinfo" class="cmtext" onclick="cmaction(1,event)"><b>Information</b></div>
38 + <div id="cxdesktop" class="cmtext" onclick="cmaction(3,event)">Desktop</div>
39 + <div id="cxterminal" class="cmtext" onclick="cmaction(2,event)">Terminal</div>
40 + <div id="cxfiles" class="cmtext" onclick="cmaction(4,event)">Files</div>
41 + <div id="cxevents" class="cmtext" onclick="cmaction(5,event)">Events</div>
42 + <div id="cxconsole" class="cmtext" onclick="cmaction(6,event)">Console</div>
43 + <hr id="cxmgroupsplit">
44 + <div id="cxmdesktop" class="cmtext" onclick="cmaction(7,event)" style="display:none">Multi-Desktop</div>
45 + </div>
46 + <div id="meshContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
47 + <div id="cxselectall" class="cmtext" onclick="cmmeshaction(1,event)">Select All</div>
48 + <div id="cxselectnone" class="cmtext" onclick="cmmeshaction(2,event)">Select None</div>
49 + <!--
50 + <hr id="cxmgroupsplit2" style="display:none" />
51 + <div id="cxmmdesktop" class="cmtext" style="display:none" onclick="cmmeshaction(3,event)">Multi-Desktop</div>
52 + -->
53 + </div>
54 + <div id="termShellContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
55 + <div id="cxtermnorm" class="cmtext" onclick="cmtermaction(1,event)">Normal Connect</div>
56 + <div id="cxtermps" class="cmtext" onclick="cmtermaction(2,event)">PowerShell Connect</div>
57 + </div>
58 + <!-- main page -->
59 + <div id="container">
60 + <div id="notifiyBox" class="notifiyBox" style="display:none"></div>
61 + <div id="masthead" class="noselect">
62 + <div class="title">{{{title}}}</div>
63 + <div class="title2">{{{title2}}}</div>
64 + <div style="float:right">
65 + <div id="notificationCount" onclick="clickNotificationIcon()" class="unselectable" style="display: none;" title="Click to view current notifications">0</div>
66 + </div>
67 + <p id="logoutControl">{{{logoutControl}}}<span id="idleTimeoutNotify" style="color:yellow"></span></p>
68 + </div>
69 + <div id="page_leftbar">
70 + <div style="height:16px"></div>
71 + <div id="LeftMenuMyDevices" tabindex="0" class="lbbutton lbbuttonsel" title="My Devices" onclick="go(1,event)" onkeypress="if (event.key=='Enter') { go(1); }">
72 + <div class="lb2"></div>
73 + </div>
74 + <div id="LeftMenuMyAccount" tabindex="0" class="lbbutton" title="My Account" onclick="go(2,event)" onkeypress="if (event.key=='Enter') { go(2); }">
75 + <div class="lb1"></div>
76 + </div>
77 + <div id="LeftMenuMyEvents" tabindex="0" class="lbbutton" title="My Events" onclick="go(3,event)" onkeypress="if (event.key=='Enter') { go(3); }">
78 + <div class="lb3"></div>
79 + </div>
80 + <div id="LeftMenuMyFiles" tabindex="0" class="lbbutton" style="display:none" title="My Files" onclick="go(5,event)" onkeypress="if (event.key=='Enter') { go(5); }">
81 + <div class="lb4"></div>
82 + </div>
83 + <div id="LeftMenuMyUsers" tabindex="0" class="lbbutton" style="display:none" title="My Users" onclick="go(4,event)" onkeypress="if (event.key=='Enter') { go(4); }">
84 + <div class="lb5"></div>
85 + </div>
86 + <div id="LeftMenuMyServer" tabindex="0" class="lbbutton" style="display:none" title="My Server" onclick="go(6,event)" onkeypress="if (event.key=='Enter') { go(6); }">
87 + <div class="lb6"></div>
88 + </div>
89 + </div>
90 + <div id="topbar" class="noselect">
91 + <div>
92 + <div style="position:relative">
93 + <div tabindex="0" id="uiMenuButton" title="User interface selection" onclick="showUserInterfaceSelectMenu()" onkeypress="if (event.key == 'Enter') showUserInterfaceSelectMenu()">
94 + ♦
95 + <div id="uiMenu" style="display:none">
96 + <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>
97 + <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>
98 + <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>
99 + <div tabindex="0" id="uiViewButton4" class="uiSelector" onclick="toggleNightMode()" title="Basculer mode nuit" onkeypress="if (event.key == 'Enter') toggleNightMode()"><div class="uiSelector4"></div></div>
100 + </div>
101 + </div>
102 + <table id="MainMenuSpan" cellpadding="0" cellspacing="0" class="style1">
103 + <tbody><tr>
104 + <td tabindex="0" id="MainMenuMyDevices" class="topbar_td style3x" onclick="go(1,event)" onkeypress="if (event.key == 'Enter') go(1)">My Devices</td>
105 + <td tabindex="0" id="MainMenuMyAccount" class="topbar_td style3x" onclick="go(2,event)" onkeypress="if (event.key == 'Enter') go(2)">My Account</td>
106 + <td tabindex="0" id="MainMenuMyEvents" class="topbar_td style3x" onclick="go(3,event)" onkeypress="if (event.key == 'Enter') go(3)">My Events</td>
107 + <td tabindex="0" id="MainMenuMyFiles" class="topbar_td style3x" onclick="go(5,event)" onkeypress="if (event.key == 'Enter') go(5)">My Files</td>
108 + <td tabindex="0" id="MainMenuMyUsers" class="topbar_td style3x" onclick="go(4,event)" onkeypress="if (event.key == 'Enter') go(4)">My Users</td>
109 + <td tabindex="0" id="MainMenuMyServer" class="topbar_td style3x" onclick="go(6,event)" onkeypress="if (event.key == 'Enter') go(6)">My Server</td>
110 + <td class="topbar_td_end style3">&nbsp;</td>
111 + </tr>
112 + </tbody></table>
113 + <div id="MainSubMenuSpan" style="display:none">
114 + <table id="MainSubMenu" cellpadding="0" cellspacing="0" class="style1">
115 + <tbody><tr>
116 + <td tabindex="0" id="MainDev" class="topbar_td style3x" onclick="go(10,event)" onkeypress="if (event.key == 'Enter') go(10)">General</td>
117 + <td tabindex="0" id="MainDevDesktop" class="topbar_td style3x" onclick="go(11,event)" onkeypress="if (event.key == 'Enter') go(11)">Desktop</td>
118 + <td tabindex="0" id="MainDevTerminal" class="topbar_td style3x" onclick="go(12,event)" onkeypress="if (event.key == 'Enter') go(12)">Terminal</td>
119 + <td tabindex="0" id="MainDevFiles" class="topbar_td style3x" onclick="go(13,event)" onkeypress="if (event.key == 'Enter') go(13)">Files</td>
120 + <td tabindex="0" id="MainDevEvents" class="topbar_td style3x" onclick="go(16,event)" onkeypress="if (event.key == 'Enter') go(16)">Events</td>
121 + <td tabindex="0" id="MainDevInfo" class="topbar_td style3x" onclick="go(17,event)" onkeypress="if (event.key == 'Enter') go(17)">Details</td>
122 + <td tabindex="0" id="MainDevAmt" class="topbar_td style3x" onclick="go(14,event)" onkeypress="if (event.key == 'Enter') go(14)">Intel® AMT</td>
123 + <td tabindex="0" id="MainDevConsole" class="topbar_td style3x" onclick="go(15,event)" onkeypress="if (event.key == 'Enter') go(15)">Console</td>
124 + <td tabindex="0" id="MainDevPlugins" class="topbar_td style3x" onclick="go(19,event)" onkeypress="if (event.key == 'Enter') go(19)">Plugins</td>
125 + <td class="topbar_td_end style3">&nbsp;</td>
126 + </tr>
127 + </tbody></table>
128 + </div>
129 + <div id="MeshSubMenuSpan" style="display:none">
130 + <table id="MeshSubMenu" cellpadding="0" cellspacing="0" class="style1">
131 + <tbody><tr>
132 + <td tabindex="0" id="MeshGeneral" class="topbar_td style3x" onclick="go(20,event)" onkeypress="if (event.key == 'Enter') go(20)">General</td>
133 + <td class="topbar_td_end style3">&nbsp;</td>
134 + </tr>
135 + </tbody></table>
136 + </div>
137 + <div id="UserSubMenuSpan" style="display:none">
138 + <table id="UserSubMenu" cellpadding="0" cellspacing="0" class="style1">
139 + <tbody><tr>
140 + <td tabindex="0" id="UserGeneral" class="topbar_td style3x" onclick="go(30,event)" onkeypress="if (event.key == 'Enter') go(30)">General</td>
141 + <td tabindex="0" id="UserEvents" class="topbar_td style3x" onclick="go(31,event)" onkeypress="if (event.key == 'Enter') go(31)">Events</td>
142 + <td class="topbar_td_end style3">&nbsp;</td>
143 + </tr>
144 + </tbody></table>
145 + </div>
146 + <div id="ServerSubMenuSpan" style="display:none">
147 + <table id="ServerSubMenu" cellpadding="0" cellspacing="0" class="style1">
148 + <tbody><tr>
149 + <td tabindex="0" id="ServerGeneral" class="topbar_td style3x" onclick="go(6,event)" onkeypress="if (event.key == 'Enter') go(6)">General</td>
150 + <td tabindex="0" id="ServerStats" class="topbar_td style3x" onclick="go(40,event)" onkeypress="if (event.key == 'Enter') go(40)">Stats</td>
151 + <td tabindex="0" id="ServerConsole" class="topbar_td style3x" onclick="go(115,event)" onkeypress="if (event.key == 'Enter') go(115)">Console</td>
152 + <td tabindex="0" id="ServerTrace" class="topbar_td style3x" onclick="go(41,event)" onkeypress="if (event.key == 'Enter') go(41)">Trace</td>
153 + <td class="topbar_td_end style3">&nbsp;</td>
154 + </tr>
155 + </tbody></table>
156 + </div>
157 + <div id="UserDummyMenuSpan">
158 + <table id="UserDummyMenu" cellpadding="0" cellspacing="0" class="style1">
159 + <tbody><tr><td class="style3" style="">&nbsp;</td></tr>
160 + </tbody></table>
161 + </div>
162 + </div>
163 + </div>
164 + </div>
165 + <div id="column_l">
166 + <div id="p0" style="display:none">
167 + <div id="p0message"><span id="p0span">Server disconnected</span>, <href onclick="reload()" style="cursor:pointer"><u>click to reconnect</u></href>.</div>
168 + </div>
169 + <div id="p1" style="display:none">
170 + <div style="display:none" id="devListToolbarViewIcons">
171 + <div tabindex="0" id="devViewButton1" class="viewSelector" onclick="onDeviceViewChange(1)" onkeypress="if (event.key == 'Enter') { onDeviceViewChange(1); }" title="Columns"><div class="viewSelector2"></div></div>
172 + <div tabindex="0" id="devViewButton2" class="viewSelector" onclick="onDeviceViewChange(2)" onkeypress="if (event.key == 'Enter') { onDeviceViewChange(2); }" title="List"><div class="viewSelector1"></div></div>
173 + <div tabindex="0" id="devViewButton3" class="viewSelector" onclick="onDeviceViewChange(3)" onkeypress="if (event.key == 'Enter') { onDeviceViewChange(3); }" title="Desktops"><div class="viewSelector3"></div></div>
174 + <div tabindex="0" id="devViewButton4" class="viewSelector" onclick="onDeviceViewChange(4)" onkeypress="if (event.key == 'Enter') { onDeviceViewChange(4); }" title="Map"><div class="viewSelector4"></div></div>
175 + </div><div><h1>My Devices</h1></div>
176 + <table id="devListToolbarSpan" class="noselect">
177 + <tbody><tr>
178 + <td class="h1"></td>
179 + <td id="devListToolbar" class="style14" style="display:none">
180 + &nbsp;&nbsp;<input type="button" id="SelectAllButton" onclick="selectallButtonFunction();" value="Select All">&nbsp;
181 + <input type="button" id="GroupActionButton" disabled="disabled" value="Group Action" onclick="groupActionFunction()">&nbsp;
182 + <input id="SearchInput" type="text" placeholder="Filter" onchange="masterUpdate(5)" onkeyup="masterUpdate(5)" autocomplete="off" onfocus="onSearchFocus(1)" onblur="onSearchFocus(0)">&nbsp;
183 + <label><input type="checkbox" id="RealNameCheckBox" onclick="onRealNameCheckBox()"><span title="Show devices operating system name">OS Name</span></label>
184 + </td>
185 + <td id="kvmListToolbar" class="style14" style="display:none">
186 + &nbsp;&nbsp;<span id="kvmMultiConnectButtonSpan"><input type="button" onclick="connectAllKvmFunction()" value="Connect All">&nbsp;</span>
187 + <input type="button" onclick="disconnectAllKvmFunction()" value="Disconnect All">&nbsp;
188 + <span id="kvmAutoConnectButtonSpan"><label><input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" title="Connexion automatique">Automatique&nbsp;</label></span>
189 + <input type="button" onclick="showMultiDesktopSettings()" value="Settings">&nbsp;
190 + </td>
191 + <td id="devMapToolbar" class="style14" style="display:none">
192 + &nbsp;&nbsp;<input type="text" id="mapSearchLocation" placeholder="Search Location" onfocus="onMapSearchFocus(1)" onblur="onMapSearchFocus(0)">
193 + <input type="button" value="Search" title="Search for location" onclick="getSearchLocation()">
194 + <input type="button" id="refreshmap" title="Reset map view" value="Reset" onclick="refreshMap(false,true)">
195 + </td>
196 + <td class="auto-style1" style="height:100%">
197 + <div style="display:none" id="devListToolbarView">
198 + View
199 + <select id="viewselect" onchange="onDeviceViewChange()">
200 + <option value="1">Columns</option>
201 + <option value="2">List</option>
202 + <option value="3">Desktops</option>
203 + <option id="viewselectmapoption" value="4">Map</option>
204 + </select>
205 + </div>
206 + <div style="display:none" id="devListToolbarSort">
207 + Sort
208 + <select id="sortselect" onchange="masterUpdate(6)">
209 + <option>Group</option>
210 + <option>Power</option>
211 + <option>Device</option>
212 + <option>Tags</option>
213 + </select>
214 + &nbsp;
215 + </div>
216 + <div style="display:none" id="devListToolbarSize">
217 + Size
218 + <select id="sizeselect" onchange="onDeviceViewChange()">
219 + <option value="0">Small</option>
220 + <option value="1">Medium</option>
221 + <option value="2">Large</option>
222 + </select>
223 + &nbsp;
224 + </div>
225 + </td>
226 + <td class="h2"></td>
227 + </tr>
228 + </tbody></table>
229 + <div id="NoMeshesPanel" style="display:none">
230 + <table>
231 + <tbody><tr>
232 + <td valign="top" style="width: 50px">
233 + <img src="images/info.png">
234 + </td>
235 + <td>
236 + <div id="getStarted1">To get started, <a href="#" onclick="return account_createMesh()"><strong>click here to create a device group</strong></a>.</div>
237 + <div id="getStarted2">No device groups.</div>
238 + </td>
239 + </tr>
240 + </tbody></table>
241 + </div>
242 + <div id="xdevices" class="noselect" style="display:none"></div>
243 + <div id="xdevicesmap" style="display:none">
244 + <div id="xmapSearchResultsDlg" style="display:none">
245 + <div id="xmapSearchResultsBck">
246 + <div id="xmapSearchClose" onclick="mapCloseSearchWindow()"><b>X</b></div>
247 + <div style="padding:5px">Location Results</div>
248 + <div style="width:100%;margin:6px"></div>
249 + </div>
250 + <div id="xmapSearchResults" style="margin:6px"></div>
251 + </div>
252 + </div>
253 + <div id="xmap-info-window"></div>
254 + </div>
255 + <div id="p2" style="display:none">
256 + <h1>My Account</h1>
257 + <img id="p2AccountImage" alt="" src="images/clipboard-128.png">
258 + <div id="p2AccountSecurity" style="display:none">
259 + <p><strong>Account security</strong></p>
260 + <div style="margin-left:25px">
261 + <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>
262 + <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>
263 + <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>
264 + </div>
265 + </div>
266 + <div id="p2AccountActions">
267 + <p><strong>Account actions</strong></p>
268 + <p class="mL">
269 + <span id="verifyEmailId" style="display:none"><a href="#" onclick="return account_showVerifyEmail()">Verify email</a><br></span>
270 + <span id="accountEnableNotificationsSpan" style="display:none"><a href="#" onclick="return account_enableNotifications()">Enable web notifications</a><br></span>
271 + <a href="#" onclick="return account_showLocalizationSettings()">Localization Settings</a><br>
272 + <a href="#" onclick="return account_showAccountNotifySettings()">Notification Settings</a><br>
273 + <span id="accountChangeEmailAddressSpan" style="display:none"><a href="#" onclick="return account_showChangeEmail()">Change email address</a><br></span>
274 + <a href="#" onclick="return account_showChangePassword()">Change password</a><span id="p2nextPasswordUpdateTime"></span><br>
275 + <a href="#" onclick="return account_showDeleteAccount()">Delete account</a><br>
276 + </p>
277 + <br style="clear:both">
278 + </div>
279 + <strong>Device Groups</strong>
280 + <span id="p2createMeshLink1">( <a href="#" onclick="return account_createMesh()" class="newMeshBtn"> New</a> )</span>
281 + <br><br>
282 + <div id="p2meshes"></div>
283 + <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>
284 + <br style="clear:both">
285 + </div>
286 + <div id="p3" style="display:none">
287 + <h1>My Events</h1>
288 + <table class="pTable">
289 + <tbody><tr>
290 + <td class="h1"></td>
291 + <td class="auto-style1">
292 + Show
293 + <select id="p3limitdropdown" onchange="refreshEvents()">
294 + <option value="60">Last 60</option>
295 + <option value="120">Last 120</option>
296 + <option value="250">Last 250</option>
297 + <option value="500">Last 500</option>
298 + <option value="1000">Last 1000</option>
299 + </select>&nbsp;
300 + <a href="#" onclick="p3showDownloadEventsDialog(2)"><img src="images/link4.png" height="10" width="10" title="Download Events" style="cursor:pointer"></a>&nbsp;
301 + </td>
302 + <td class="h2"></td>
303 + </tr>
304 + </tbody></table>
305 + <div id="p3events" style=""></div>
306 + </div>
307 + <div id="p4" style="display:none">
308 + <h1>My Users</h1>
309 + <table class="pTable">
310 + <tbody><tr>
311 + <td class="h1"></td>
312 + <td class="style14">
313 + <div style="float:right">
314 + <input type="button" onclick="showUserBroadcastDialog()" style="margin-right:6px" value="Diffuser">
315 + <a href="#" onclick="p4downloadUserInfo()"><img style="cursor:pointer" title="Download user information" src="images/link4.png"></a>
316 + <a href="#" onclick="p4batchAccountCreate()"><img id="p4UserBatchCreate" style="cursor:pointer;display:none" title="Batch create many user accounts" src="images/link6.png"></a>
317 + </div>
318 + <div>
319 + <input id="UserNewAccountButton" type="button" style="margin-left:6px" onclick="showCreateNewAccountDialog()" value="New Account...">
320 + <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)">
321 + </div>
322 + </td>
323 + <td class="h2"></td>
324 + </tr>
325 + </tbody></table>
326 + <div id="p3users"></div>
327 + </div>
328 + <div id="p5" style="display:none">
329 + <h1>My Files</h1>
330 + <table id="p5toolbar" cellpadding="0" cellspacing="0">
331 + <tbody><tr>
332 + <td id="p5filehead" valign="bottom">
333 + <div id="p5rightOfButtons"></div>
334 + <div>
335 + <input type="button" id="p5FolderUp" disabled="disabled" onclick="return p5folderup();" value="Up">&nbsp;
336 + <input type="button" id="p5SelectAllButton" disabled="disabled" onclick="p5selectallfile();" value="Select All">&nbsp;
337 + <input type="button" id="p5RenameFileButton" disabled="disabled" value="Rename" onclick="p5renamefile();">&nbsp;
338 + <input type="button" id="p5DeleteFileButton" disabled="disabled" value="Delete" onclick="p5deletefile();">&nbsp;
339 + <!--<input type=button id=p5ViewFileButton disabled="disabled" value="View" onclick="p5viewfile()" />&nbsp;-->
340 + <input type="button" id="p5NewFolderButton" disabled="disabled" value="New Folder" onclick="p5createfolder();">&nbsp;
341 + <input type="button" id="p5UploadButton" disabled="disabled" value="Télécharger" onclick="p5uploadFile()">&nbsp;
342 + <input type="button" id="p5CutButton" disabled="disabled" value="Cut" onclick="p5copyFile(1)">&nbsp;
343 + <input type="button" id="p5CopyButton" disabled="disabled" value="Copy" onclick="p5copyFile(0)">&nbsp;
344 + <input type="button" id="p5PasteButton" disabled="disabled" value="Paste" onclick="p5pasteFile()">&nbsp;
345 + </div>
346 + </td>
347 + </tr>
348 + <tr>
349 + <td id="p5filesubhead">
350 + <div style="float:right">
351 + <select id="p5sortdropdown" onchange="updateFiles()">
352 + <option value="1" selected="selected">Sort by name</option>
353 + <option value="2">Sort by size</option>
354 + <option value="3">Sort by date</option>
355 + <option value="4">Descend by name</option>
356 + <option value="5">Descend by size</option>
357 + <option value="6">Descend by date</option>
358 + </select>
359 + </div>
360 + <div>&nbsp;&nbsp;<span id="p5currentpath"></span></div>
361 + </td>
362 + </tr>
363 + </tbody></table>
364 + <div id="p5filetable">
365 + <!--
366 + <form id=p5fileCatchAll method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame>
367 + <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)" />
368 + <input id=p5fileDragLink2 name="link" style="display:none" />
369 + <input type=submit id=p5fileCatchAllSubmit style="display:none" />
370 + </form>
371 + -->
372 + <div id="p5PublicShare" style=""><div>Ces fichiers sont partagés publiquement, cliquez sur "lien" pour obtenir une URL publique.</div></div>
373 + <div id="bigok" style="display:none"><b>✓</b></div>
374 + <div id="bigfail" style="display:none"><b>✗</b></div>
375 + <span id="p5files"></span>
376 + </div>
377 + <table id="p5toolbarBottom" style="width:100%" cellpadding="0" cellspacing="0">
378 + <tbody><tr><td class="style6">&nbsp;<span id="p5bottomstatus"></span></td></tr>
379 + </tbody></table>
380 + </div>
381 + <div id="p6" style="display:none">
382 + <img id="MainMeshImage" src="serverpic.ashx">
383 + <h1>My Server</h1>
384 + <div id="p2ServerActions">
385 + <p><strong>Server actions</strong></p>
386 + <div class="mL">
387 + <div id="p2ServerActionsBackup"><a href="{{{domainurl}}}backup.zip" rel="noreferrer noopener" target="_blank">Download server backup</a></div>
388 + <div id="p2ServerActionsRestore"><a href="#" onclick="return server_showRestoreDlg()">Restore server with backup</a></div>
389 + <div id="p2ServerActionsVersion"><a href="#" onclick="return server_showVersionDlg()">Check server version</a></div>
390 + <div id="p2ServerActionsErrors"><a href="#" onclick="return server_showErrorsDlg()">Show server error log</a></div>
391 + </div>
392 + </div>
393 + <br><strong>Server Statistics</strong><br><br>
394 + <div id="serverStats">
395 + <div id="serverCpuChartView" style="display:none">
396 + <div class="chartViewCanvas"><canvas id="serverCpuChart"></canvas></div>
397 + <div class="chartViewText" id="serverCpuChartText"></div>
398 + </div>
399 + <div id="serverMemoryChartView" style="display:none">
400 + <div class="chartViewCanvas"><canvas id="serverMemoryChart"></canvas></div>
401 + <div class="chartViewText" id="serverMemoryChartText"></div>
402 + </div><br><br>
403 + <div id="serverStatsTable"></div>
404 + </div>
405 + </div>
406 + <div id="p10" style="display:none">
407 + <table style="width:100%" cellpadding="0" cellspacing="0">
408 + <tbody><tr>
409 + <td style="width:auto" valign="top">
410 + <div id="p10title">
411 + <div id="p10BackButton"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
412 + <h1>General - <span id="p10deviceName"></span></h1>
413 + </div>
414 + <div id="p10html"></div>
415 + </td>
416 + <td style="width:20px"></td>
417 + <td style="width:200px">
418 + <a href="#" onclick="p10showiconselector()"><img id="MainComputerImage"></a>
419 + <div id="MainComputerState"></div>
420 + </td>
421 + </tr>
422 + </tbody></table><br>
423 + <div id="p10html2"></div>
424 + <div id="p10html3"></div>
425 + </div>
426 + <div id="p11" class="noselect" style="display:none">
427 + <div id="p11title">
428 + <div id="p11deviceNameHeader">
429 + <div id="p11BackButton"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
430 + <div id="devListToolbarViewIcons"><div class="viewSelector" onclick="deskToggleFull(event)" title="Full Screen. Hold shift to browser full screen."><div class="viewSelector5"></div></div></div>
431 + <h1>Desktop - <span id="p11deviceName"></span></h1>
432 + </div>
433 + </div>
434 + <div id="p11warning" onclick="showFeaturesDlg()">
435 + <div class="icon2"></div>
436 + <div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p11warninga">, click here to enable it.</span></div>
437 + </div>
438 + <div id="p11warning2" onclick="showPowerActionDlg()">
439 + <div class="icon2"></div>
440 + <div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
441 + </div>
442 + <div id="deskarea0" cellpadding="0" cellspacing="0">
443 + <div id="deskarea1" class="areaHead">
444 + <div class="toright2">
445 + <span id="p11power"></span>&nbsp;
446 + <div class="deskareaicon" title="Toggle View Mode" onclick="toggleAspectRatio(1)">⇲</div>
447 + <div class="deskareaicon" title="Rotate Left" onclick="drotate(-1)">↺</div>
448 + <div class="deskareaicon" title="Rotate Right" onclick="drotate(1)">↻</div>
449 + <div id="deskRecordIcon" class="deskareaicon" title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px"></div>
450 + <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">
451 + <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">
452 + <input id="deskActionsBtn" type="button" title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value="Actions" onclick="deviceActionFunction()" class="mR">
453 + <input id="deskActionsSettings" type="button" value="Paramètres..." title="Edit remote desktop settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" class="mR">
454 + <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">
455 + </div>
456 + <div>
457 + <div id="idx_deskFullBtn2" onclick="deskToggleFull(event)">&nbsp;✖</div>
458 + <input type="button" id="autoconnectbutton1" value="AutoConnect" onclick="autoConnectDesktop(event)" onkeypress="return false" onkeydown="return false" style="display:none">
459 + <span id="connectbutton1span"><input type="button" id="connectbutton1" value="Connect" onclick="connectDesktop(event,1)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
460 + <span id="connectbutton1hspan">&nbsp;<input type="button" id="connectbutton1h" value="HW Connect" onclick="connectDesktop(event,2)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
461 + <span id="disconnectbutton1span">&nbsp;<input type="button" id="disconnectbutton1" value="Disconnect" onclick="connectDesktop(event,0)" onkeypress="return false" onkeydown="return false"></span>
462 + &nbsp;<span id="deskstatus">Disconnected</span>
463 + </div>
464 + </div>
465 + <div id="deskarea2" style="">
466 + <div class="areaProgress"><div id="progressbar" style=""></div></div>
467 + </div>
468 + <div id="deskarea3x">
469 + <div id="DeskFocus" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></div>
470 + <div id="DeskParent">
471 + <canvas id="Desk" width="640" height="480" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)" onmousewheel="dmousewheel(event)"></canvas>
472 + </div>
473 + <div id="DeskTools">
474 + <div id="deskToolsAreaTop">
475 + <a id="DeskToolsRefreshButton" style="right:2px" onclick="refreshDeskTools()">Refresh</a>
476 + <div id="deskToolsTopTabProcess" class="deskToolsTopTab" onclick="changeDeskToolTab(0)" style="left:0px;bottom:0px">Processes</div>
477 + <div id="deskToolsTopTabService" class="deskToolsTopTab" onclick="changeDeskToolTab(1)" style="display:none;left:90px;color:gray">Services</div>
478 + </div>
479 + <div id="deskToolsArea">
480 + <div id="DeskToolsProcessTab">
481 + <div id="deskToolsHeader">
482 + <a class="colmn1" title="Sort by process id" onclick="sortProcess(0)">PID</a>
483 + <a class="colmn2" title="Sort by name" onclick="sortProcess(1)">Name</a>
484 + </div>
485 + <div id="DeskToolsProcesses" style=""></div>
486 + </div>
487 + <div id="DeskToolsServiceTab" style="display:none">
488 + <div id="deskToolsServiceHeader">
489 + <a class="colmn1" style="width:70px" title="Sort by state" onclick="sortService(0)">State</a>
490 + <a class="colmn2" title="Sort by name" onclick="sortService(1)">Name</a>
491 + </div>
492 + <div id="DeskToolsServices" style=""></div>
493 + </div>
494 + </div>
495 + </div>
496 + <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>
497 + </div>
498 + <div id="deskarea4" class="areaFoot">
499 + <div class="toright2">
500 + <span id="DeskTimer" title="Session time"></span>&nbsp;
501 + <select id="termdisplays" style="display:none" onchange="deskSetDisplay(event)" onkeypress="return false" onkeydown="return false"></select>&nbsp;
502 + <input id="DeskToolsButton" type="button" value="Outils" title="Toggle tools view" onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()">&nbsp;
503 + <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>
504 + <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>
505 + <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>
506 + </div>
507 + <div>
508 + <select id="deskkeys">
509 + <option value="10">Ctrl+Alt+Del</option>
510 + <option value="5">Win</option>
511 + <option value="0">Win+Down</option>
512 + <option value="1">Win+Up</option>
513 + <option value="2">Win+L</option>
514 + <option value="3">Win+M</option>
515 + <option value="4">Shift+Win+M</option>
516 + <option value="6">Win+R</option>
517 + <option value="7">Alt-F4</option>
518 + <option value="8">Ctrl-W</option>
519 + <option value="9">Alt-Tab</option>
520 + <option value="11">Win+Left</option>
521 + <option value="12">Win+Right</option>
522 + </select>
523 + <input id="DeskWD" type="button" value="Send" onkeypress="return false" onkeydown="return false" onclick="deskSendKeys()">
524 + <input id="DeskClip" style="" type="button" value="Clipboard" onkeypress="return false" onkeydown="return false" onclick="showDeskClip()">
525 + <input id="DeskType" style="" type="button" value="Type" onkeypress="return false" onkeydown="return false" onclick="showDeskType()">
526 + <label><span id="DeskControlSpan" title="Basculer la souris et le clavier"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false" onclick="toggleKvmControl()">Input</span></label>&nbsp;
527 + </div>
528 + </div>
529 + </div>
530 + </div>
531 + <div id="p12" style="display:none">
532 + <div id="p12title">
533 + <div id="p12BackButton"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
534 + <h1>Terminal - <span id="p12deviceName"></span></h1>
535 + </div>
536 + <div id="p12warning" onclick="showFeaturesDlg()">
537 + <div class="icon2"></div>
538 + <div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p12warninga">, click here to enable it.</span></div>
539 + </div>
540 + <div id="p12warning2" onclick="showPowerActionDlg()">
541 + <div class="icon2"></div>
542 + <div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
543 + </div>
544 + <div id="termTable" style="position:relative">
545 + <table style="width:100%" cellpadding="0" cellspacing="0">
546 + <tbody><tr>
547 + <td class="areaHead">
548 + <div class="toright2">
549 + <div id="termRecordIcon" class="deskareaicon" title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-left:5px"></div>
550 + <input id="termActionsBtn" type="button" title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value="Actions" onclick="deviceActionFunction()">
551 + </div>
552 + <div>
553 + <input type="button" id="autoconnectbutton2" value="AutoConnect" onclick="autoConnectTerminal(event)" onkeypress="return false" onkeydown="return false" style="display:none">
554 + <span id="connectbutton2span"><input type="button" id="connectbutton2" value="Connect" onclick="connectTerminal(event,1)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
555 + <span id="connectbutton2hspan">&nbsp;<input type="button" id="connectbutton2h" value="HW Connect" onclick="connectTerminal(event,2)" onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
556 + <span id="disconnectbutton2span">&nbsp;<input type="button" id="disconnectbutton2" value="Disconnect" onclick="connectTerminal(event,0)" onkeypress="return false" onkeydown="return false"></span>
557 + &nbsp;<span id="termstatus">Disconnected</span><span id="termtitle"></span>
558 + </div>
559 + </td>
560 + </tr>
561 + <tr>
562 + <td>
563 + <div class="areaProgress"><div id="termprogressbar" style=""></div></div>
564 + </td>
565 + </tr>
566 + <tr>
567 + <td id="termarea3x">
568 + <pre id="Term"></pre>
569 + </td>
570 + </tr>
571 + <tr>
572 + <td class="areaFoot">
573 + <div class="toright2">
574 + <span id="TermTimer" title="Session time"></span>&nbsp;
575 + <span id="terminalSettingsButtons" style="display:none">
576 + <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()">
577 + <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()">
578 + <input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Basculer le type d'émulation de terminal" onclick="termToggleType()">
579 + </span>
580 + <span id="terminalSizeDropDown">
581 + <select id="termSizeList" onkeypress="return false"><option value="1">80x25</option><option value="2">100x30</option><option value="3" selected="">Automatique</option></select>
582 + </span>
583 + <select id="specialkeylist" onkeypress="return false"></select>
584 + <input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()">
585 + </div>
586 + <div>
587 + &nbsp;
588 + <input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')">
589 + <input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')">
590 + <input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')">
591 + <input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Retour arrière" onclick="termSendKey(8,'bsbutton')">
592 + <input type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()">
593 + </div>
594 + </td>
595 + </tr>
596 + </tbody></table>
597 + <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>
598 + </div>
599 + </div>
600 + <div id="p13" style="display:none">
601 + <div id="p13title">
602 + <div id="p13BackButton" style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
603 + <h1>Files - <span id="p13deviceName"></span></h1>
604 + </div>
605 + <table id="p13toolbar" cellpadding="0" cellspacing="0">
606 + <tbody><tr>
607 + <td class="areaHead">
608 + <div class="toright2">
609 + <input id="filesActionsBtn" type="button" title="Perform power actions on the device" value="Actions" onclick="deviceActionFunction()">
610 + <div id="filesRecordIcon" class="deskareaicon" title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-left:5px"></div>
611 + </div>
612 + <div>
613 + <input id="p13AutoConnect" value="AutoConnect" onclick="autoConnectFiles(event)" type="button" style="display:none">
614 + <input id="p13Connect" value="Connect" onclick="connectFiles(event)" type="button">
615 + <span id="p13Status">Disconnected</span>
616 + </div>
617 + </td>
618 + </tr>
619 + <tr>
620 + <td class="areaHead2" valign="bottom">
621 + <div id="p13rightOfButtons" class="toright2"></div>
622 + <div>
623 + <input type="button" id="p13FolderUp" disabled="disabled" onclick="p13folderup()" value="Up">&nbsp;
624 + <input type="button" id="p13SelectAllButton" disabled="disabled" onclick="p13selectallfile()" value="Select All">&nbsp;
625 + <input type="button" id="p13RenameFileButton" disabled="disabled" value="Rename" onclick="p13renamefile()">&nbsp;
626 + <input type="button" id="p13DeleteFileButton" disabled="disabled" value="Delete" onclick="p13deletefile()">&nbsp;
627 + <input type="button" id="p13ViewFileButton" disabled="disabled" value="Edit" onclick="p13viewfile()">&nbsp;
628 + <input type="button" id="p13NewFolderButton" disabled="disabled" value="New Folder" onclick="p13createfolder()">&nbsp;
629 + <input type="button" id="p13UploadButton" disabled="disabled" value="Télécharger" onclick="p13uploadFile()">&nbsp;
630 + <input type="button" id="p13CutButton" disabled="disabled" value="Cut" onclick="p13copyFile(1)">&nbsp;
631 + <input type="button" id="p13CopyButton" disabled="disabled" value="Copy" onclick="p13copyFile(0)">&nbsp;
632 + <input type="button" id="p13PasteButton" disabled="disabled" value="Paste" onclick="p13pasteFile()">&nbsp;
633 + <input type="button" id="p13RefreshButton" disabled="disabled" value="Refresh" onclick="p13folderup(9999)">&nbsp;
634 + </div>
635 + </td>
636 + </tr>
637 + <tr>
638 + <td class="areaHead3">
639 + <div class="toright2">
640 + <select id="p13sortdropdown" onchange="p13updateFiles()">
641 + <option value="1" selected="selected">Sort by name</option>
642 + <option value="2">Sort by size</option>
643 + <option value="3">Sort by date</option>
644 + <option value="4">Descend by name</option>
645 + <option value="5">Descend by size</option>
646 + <option value="6">Descend by date</option>
647 + </select>
648 + </div>
649 + <div>&nbsp;&nbsp;<span id="p13currentpath"></span></div>
650 + </td>
651 + </tr>
652 + </tbody></table>
653 + <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>
654 + <div id="p13filetable" style="">
655 + <div id="p13bigok" style="display:none"><b>✓</b></div>
656 + <div id="p13bigfail" style="display:none"><b>✗</b></div>
657 + <span id="p13files"></span>
658 + </div>
659 + <table id="p13toolbarBottom" cellpadding="0" cellspacing="0">
660 + <tbody><tr><td class="style6">&nbsp;<span id="p13bottomstatus"></span></td></tr>
661 + </tbody></table>
662 + </div>
663 + <div id="p14" style="display:none">
664 + <div id="p14title">
665 + <div id="p14BackButton" style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
666 + <div id="devListToolbarViewIcons"><div class="viewSelector" onclick="deskToggleFull(event)" title="Full Screen. Hold shift to browser full screen."><div class="viewSelector5"></div></div></div>
667 + <h1>Intel® AMT - <span id="p14deviceName"></span></h1>
668 + </div>
669 + <iframe id="p14iframe" src="{{{domainurl}}}commander.htm"></iframe>
670 + </div>
671 + <div id="p15" style="display:none">
672 + <div id="p15title">
673 + <div id="p15BackButton" style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
674 + <h1><span id="p15deviceName"></span></h1>
675 + </div>
676 + <table id="consoleTable" cellpadding="0" cellspacing="0">
677 + <tbody><tr>
678 + <td class="areaHead">
679 + <div class="toright2">
680 + <div id="p15coreName" title="Information about current core running on this agent"></div>
681 + <input type="button" id="p15uploadCore" value="Agent Action" onclick="p15uploadCore(event)" title="Change the agent Java Script code module">
682 + <img onclick="p15downloadConsoleText()" style="cursor:pointer;margin-top:6px" title="Download console text" src="images/link4.png">
683 + </div>
684 + <div id="p15statetext"></div>
685 + </td>
686 + </tr>
687 + <tr>
688 + <td>
689 + <div class="areaProgress"><div id="consoleprogressbar" style=""></div></div>
690 + </td>
691 + </tr>
692 + <tr>
693 + <td id="p15agentConsole">
694 + <pre id="p15agentConsoleText"></pre>
695 + </td>
696 + </tr>
697 + <tr>
698 + <td class="areaFoot">
699 + <table style="width:100%">
700 + <tbody><tr>
701 + <td style="width:99%">
702 + <input id="p15consoleText" style="width:100%" onkeyup="p15consoleSend(event)" onfocus="onConsoleFocus(1)" onblur="onConsoleFocus(0)">
703 + </td>
704 + <td>&nbsp;</td>
705 + <td id="p15outputselecttd">
706 + <select id="p15outputselect">
707 + <option value="1">Agent</option>
708 + <option value="2">MQTT</option>
709 + </select>
710 + </td>
711 + <td style="width:1%"><input id="id_p15consoleClear" type="button" class="bottombutton" value="Clear" onclick="p15consoleClear()"></td>
712 + </tr>
713 + </tbody></table>
714 + </td>
715 + </tr>
716 + </tbody></table>
717 + </div>
718 + <div id="p16" style="display:none">
719 + <div id="p16title">
720 + <div id="p16BackButton" style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
721 + <h1>Events - <span id="p16deviceName"></span></h1>
722 + </div>
723 + <table class="pTable">
724 + <tbody><tr>
725 + <td class="h1"></td>
726 + <!--<td>&nbsp;<input type=button onclick=refreshDeviceEvents() value="Refresh" /></td>-->
727 + <td class="auto-style1">
728 + Show
729 + <select id="p16limitdropdown" onchange="refreshDeviceEvents()">
730 + <option value="60">Last 60</option>
731 + <option value="120">Last 120</option>
732 + <option value="250">Last 250</option>
733 + <option value="500">Last 500</option>
734 + <option value="1000">Last 1000</option>
735 + </select>
736 + <a href="#" onclick="p3showDownloadEventsDialog(1)"><img src="images/link4.png" height="10" width="10" title="Download Events" style="cursor:pointer"></a>&nbsp;
737 + </td>
738 + <td class="h2"></td>
739 + </tr>
740 + </tbody></table>
741 + <div id="p16events"></div>
742 + </div>
743 + <div id="p17" style="display:none">
744 + <div id="p17title">
745 + <div id="p17BackButton" style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
746 + <h1>Details - <span id="p17deviceName"></span></h1>
747 + </div>
748 + <div id="p17info"></div>
749 + </div>
750 + <div id="p20" style="display:none">
751 + <picture id="MainMeshImage" style="border-width:0px;height:200px;width:200px;float:right">
752 + <source type="image/webp" width="200" height="200" srcset="images/webp/mesh-256.webp">
753 + <img alt="" width="200" height="200" src="images/mesh-256.png">
754 + </picture>
755 + <div style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
756 + <h1>General - <span id="p20meshName"></span></h1>
757 + <p id="p20info"></p>
758 + </div>
759 + <div id="p30" style="display:none">
760 + <table style="width:100%" cellpadding="0" cellspacing="0">
761 + <tbody><tr>
762 + <td style="width:auto" valign="top">
763 + <div id="p30title">
764 + <div style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
765 + <h1>General - <span id="p30userName"></span></h1>
766 + </div>
767 + <div id="p30html"></div>
768 + </td>
769 + <td style="width:20px"></td>
770 + <td style="width:200px">
771 + <picture id="MainUserImage" style="border-width:0px;height:200px;width:200px;float:right">
772 + <source type="image/webp" width="200" height="200" srcset="images/webp/user-256.webp">
773 + <img alt="" width="200" height="200" src="images/user-256.png">
774 + </picture>
775 + <div style="width:100%;text-align:center"><strong><span id="MainUserState"></span></strong></div>
776 + </td>
777 + </tr>
778 + </tbody></table><br>
779 + <div id="p30html2"></div>
780 + <div id="p30html3"></div>
781 + </div>
782 + <div id="p31" style="display:none">
783 + <div style="float:left"><div class="backButton" tabindex="0" onclick="goBack()" title="Retour" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
784 + <h1>Events - <span id="p31userName"></span></h1>
785 + <table class="pTable">
786 + <tbody><tr>
787 + <td class="h1"></td>
788 + <!--<td>&nbsp;<input type=button onclick=refreshUsersEvents() value="Refresh" /></td>-->
789 + <td class="auto-style1">
790 + Show
791 + <select id="p31limitdropdown" onchange="refreshUsersEvents()">
792 + <option value="60">Last 60</option>
793 + <option value="120">Last 120</option>
794 + <option value="250">Last 250</option>
795 + <option value="500">Last 500</option>
796 + <option value="1000">Last 1000</option>
797 + </select>
798 + <a href="#" onclick="p3showDownloadEventsDialog(3)"><img src="images/link4.png" height="10" width="10" title="Download Events" style="cursor:pointer"></a>&nbsp;
799 + </td>
800 + <td class="h2"></td>
801 + </tr>
802 + </tbody></table>
803 + <div id="p31events" style=""></div>
804 + </div>
805 + <div id="p40" style="display:none">
806 + <h1>My Server Stats</h1>
807 + <div class="areaHead">
808 + <div class="toright2">
809 + <select id="p40type" onchange="updateServerTimelineStats()">
810 + <option value="0">Connections</option>
811 + <option value="1">Memory</option>
812 + </select>&nbsp;
813 + <select id="p40time" onchange="updateServerTimelineHours()">
814 + <option value="3">Last 3 hours</option>
815 + <option value="8">Last 8 hours</option>
816 + <option value="24">Last day</option>
817 + <option value="168">Last week</option>
818 + <option value="720">Last 30 days</option>
819 + </select>&nbsp;
820 + <img src="images/link4.png" height="10" width="10" title="Download data points (.csv)" style="cursor:pointer" onclick="p40downloadEvents()">&nbsp;
821 + </div>
822 + <div>
823 + <input value="Refresh" type="button" onclick="refreshServerTimelineStats()">
824 + &nbsp;<label><input id="p40log" type="checkbox" onclick="updateServerTimelineHours()">Log-X</label>
825 + </div>
826 + </div>
827 + <canvas id="serverMainStats" style=""></canvas>
828 + </div>
829 + <div id="p41" style="display:none">
830 + <h1>My Server Tracing</h1>
831 + <div class="areaHead">
832 + <div class="toright2">
833 + Show
834 + <select id="p41limitdropdown" onchange="displayServerTrace()">
835 + <option value="100">Last 100</option>
836 + <option value="250">Last 250</option>
837 + <option value="500">Last 500</option>
838 + <option value="1000">Last 1000</option>
839 + </select>
840 + <input value="Clear" type="button" onclick="clearServerTracing()">
841 + <img src="images/link4.png" height="10" width="10" title="Download trace (.csv)" style="cursor:pointer" onclick="p41downloadServerTrace()">&nbsp;
842 + </div>
843 + <div>
844 + <input value="Tracing" type="button" onclick="setServerTracing()">
845 + <span id="p41traceStatus">None</span>
846 + </div>
847 + </div>
848 + <div id="p41events" style=""></div>
849 + </div>
850 + <div id="p19" style="display:none">
851 + <h1>Plugins - <span id="p19deviceName"></span></h1>
852 + <style>
853 + #p19headers {
854 + padding-right: 7px;
855 + padding-bottom: 10px;
856 + font-weight: bold;
857 + border-bottom: 1px dotted blue;
858 + }
859 +
860 + #p19headers > span:nth-child(n+2) {
861 + border-left: 1px solid black;
862 + }
863 +
864 + #p19headers > span {
865 + padding-left: 4px;
866 + padding-right: 4px;
867 + }
868 + </style>
869 + <div id="p19headers"></div>
870 + <div id="p19pages"></div>
871 + </div>
872 + <br id="column_l_bottomgap">
873 + </div>
874 + <div id="footer">
875 + <div class="footer1">{{{footer}}}</div>
876 + <div class="footer2">
877 + <a id="verifyEmailId2" style="display:none" href="#" onclick="account_showVerifyEmail()">Verify Email</a>
878 + &nbsp;<a href="terms">Terms &amp; Privacy</a>
879 + </div>
880 + </div>
881 + <div id="dialog" class="noselect" style="display:none">
882 + <div id="dialogHeader">
883 + <div tabindex="0" id="id_dialogclose" onclick="setDialogMode()" onkeypress="if (event.key == 'Enter') setDialogMode()">✖</div>
884 + <div id="id_dialogtitle"></div>
885 + </div>
886 + <div id="dialogBody">
887 + <div id="dialog1">
888 + <div id="id_dialogMessage" style=""></div>
889 + </div>
890 + <div id="dialog2" style="">
891 + <div id="id_dialogOptions"></div>
892 + </div>
893 + <div id="dialog3" style="">
894 + <div id="d3upload">
895 + <div>File Selection</div>
896 + <select id="d3uploadMode" onchange="d3modechange()">
897 + <option value="1">Local file upload</option>
898 + <option value="2">Server file selection</option>
899 + </select>
900 + </div>
901 + <div id="d3localmode" style="display:none">
902 + <div>Upload File</div>
903 + <form id="d3localmodeform" method="post" enctype="multipart/form-data" action="uploadfile.ashx" target="fileUploadFrame">
904 + <input type="text" id="d3auth" name="auth" style="display:none">
905 + <input type="text" id="d3attrib" name="attrib" style="display:none">
906 + <input type="file" id="d3localFile" name="files" onchange="d3setActions()">
907 + <input type="submit" id="d3submit" style="display:none">
908 + </form>
909 + </div>
910 + <div id="d3servermode">
911 + <div id="d3serveraction" valign="bottom">
912 + <input type="button" id="p3FolderUp" disabled="disabled" onclick="d3folderup()" value="Up">&nbsp;
913 + </div>
914 + <div id="d3serverfiles"></div>
915 + </div>
916 + </div>
917 + <div id="dialog7" style="">
918 + <div id="d7meshkvm">
919 + <h4>Agent Remote Desktop</h4>
920 + <div>
921 + <div>Quality</div>
922 + <select id="d7bitmapquality" dir="rtl"></select>
923 + </div>
924 + <div>
925 + <div>Scaling</div>
926 + <select id="d7bitmapscaling" style="" dir="rtl">
927 + <option selected="selected" value="1024">100%</option>
928 + <option value="896">87.5%</option>
929 + <option value="768">75%</option>
930 + <option value="640">62.5%</option>
931 + <option value="512">50%</option>
932 + <option value="384">37.5%</option>
933 + <option value="256">25%</option>
934 + <option value="128">12.5%</option>
935 + </select>
936 + </div>
937 + <div>
938 + <div>Frame rate</div>
939 + <select id="d7framelimiter" dir="rtl">
940 + <option selected="selected" value="50">Fast</option>
941 + <option value="100">Medium</option>
942 + <option value="400">Slow</option>
943 + <option value="1000">Very slow</option>
944 + </select>
945 + </div>
946 + </div>
947 + <div id="d7amtkvm">
948 + <h4>Intel® AMT Hardware KVM</h4>
949 + <div>
950 + <div>Image Encoding</div>
951 + <select id="d7desktopmode">
952 + <option value="1">RLE8, Fastest</option>
953 + <option value="2">RLE16, Recommended</option>
954 + <option value="3">RAW8, Slow</option>
955 + <option value="4">RAW16, Very Slow</option>
956 + </select>
957 + </div>
958 + <div>
959 + <div>Other Settings</div>
960 + <div id="d7otherset" style="display:block">
961 + <label style="display:block"><input type="checkbox" id="d7showfocus">Show Focus Tool</label>
962 + <label style="display:block"><input type="checkbox" id="d7showcursor">Show Local Mouse Cursor</label>
963 + <label style="display:block"><input type="checkbox" id="d7localKeyMap">Local Keyboard Map</label>
964 + </div>
965 + </div>
966 + </div>
967 + </div>
968 + </div>
969 + <div id="idx_dlgButtonBar">
970 + <input id="idx_dlgCancelButton" type="button" value="Annuler" style="" onclick="dialogclose(0)">
971 + <input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)">
972 + <div><input id="idx_dlgDeleteButton" type="button" value="Delete" style="display:none" onclick="dialogclose(2)"></div>
973 + </div>
974 + </div>
975 + <iframe name="fileUploadFrame" style="display:none"></iframe>
976 + <form style="display:none" method="post" action="uploadfile.ashx" enctype="multipart/form-data" target="fileUploadFrame"><input id="p5fileDragName" name="name"><input id="p5fileDragAuthCookie" name="auth"><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>
977 + <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>
978 + <audio id="chimes"><source src="sounds/chimes.mp3" type="audio/mp3"></audio>
979 + </div>
980 + <script type="text/javascript">
981 + 'use strict';
982 +
983 + // Process server-side web state
984 + var webState = '{{{webstate}}}';
985 + if (webState != '') { webState = JSON.parse(decodeURIComponent(webState)); }
986 + for (var i in webState) { localStorage.setItem(i, webState[i]); }
987 + if (!webState.loctag) { delete localStorage.removeItem('loctag'); }
988 +
989 + var args;
990 + var autoReconnect = true;
991 + var powerStatetable = ['', "Powered", "Sleep", "Sleep", "Sleep", "Hibernating", "Power off", "Present"];
992 + var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected", "Intel&reg; AMT Connected"];
993 + var sort = 0;
994 + var searchFocus = 0;
995 + var mapSearchFocus = 0;
996 + var userSearchFocus = 0;
997 + var consoleFocus = 0;
998 + var showRealNames = false;
999 + var meshserver = null;
1000 + var meshes = {};
1001 + var meshcount = 0;
1002 + var nodes = null;
1003 + var filetree = {};
1004 + var userinfo = null;
1005 + var serverinfo = null;
1006 + var events = [];
1007 + var users = null;
1008 + var wssessions = null;
1009 + var nodeShortIdent = 0;
1010 + var desktop;
1011 + var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 50, localkeymap: false };
1012 + var multidesktopsettings = { quality: 20, scaling: 128, framerate: 1000 };
1013 + var terminal;
1014 + var files;
1015 + var debugLevel = parseInt('{{{debuglevel}}}');
1016 + var features = parseInt('{{{features}}}');
1017 + var sessionTime = parseInt('{{{sessiontime}}}');
1018 + var domain = '{{{domain}}}';
1019 + var domainUrl = '{{{domainurl}}}';
1020 + var authCookie = '{{{authCookie}}}';
1021 + var authRelayCookie = '{{{authRelayCookie}}}';
1022 + var authCookieRenewTimer = null;
1023 + var multiDesktop = {};
1024 + var multiDesktopFilter = null;
1025 + var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
1026 + var amtScanResults = null;
1027 + var debugmode = 0;
1028 + var clickOnce = (((features & 256) != 0) && detectClickOnce());
1029 + var attemptWebRTC = ((features & 128) != 0);
1030 + var passRequirements = '{{{passRequirements}}}';
1031 + if (passRequirements != '') { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
1032 + var deskAspectRatio = 0;
1033 + try { deskAspectRatio = parseInt(getstore('deskAspectRatio', '0')); } catch (ex) { }
1034 + var uiMode = parseInt(getstore('uiMode', 1));
1035 + var webPageStackMenu = false;
1036 + var webPageFullScreen = true;
1037 + var nightMode = (getstore('_nightMode', '0') == '1');
1038 + var sessionActivity = Date.now();
1039 + var updateSessionTimer = null;
1040 + var pluginHandlerBuilder = {{{pluginHandler}}};
1041 + var pluginHandler = null;
1042 + if (pluginHandlerBuilder != null) { pluginHandler = new pluginHandlerBuilder(); }
1043 +
1044 + // Console Message Display Timers
1045 + var p11DeskConsoleMsgTimer = null;
1046 + var p12TermConsoleMsgTimer = null;
1047 + var p13FilesConsoleMsgTimer = null;
1048 +
1049 + function startup() {
1050 + if ((features & 32) == 0) {
1051 + // Guard against other site's top frames (web bugs).
1052 + var loc = null;
1053 + try { loc = top.location.toString().toLowerCase(); } catch (e) { }
1054 + if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
1055 + }
1056 +
1057 + // Check if we are in debug mode
1058 + args = parseUriArgs();
1059 + if (!args.locale) { var x = getstore('loctag', 0); if ((x != null) && (x != '*')) { args.locale = x; } }
1060 + debugmode = args.debug;
1061 + if (args.webrtc != null) { attemptWebRTC = (args.webrtc == 1); }
1062 + QV('p13AutoConnect', debugmode); // Files
1063 + QV('autoconnectbutton2', debugmode); // Terminal
1064 + QV('autoconnectbutton1', debugmode); // Desktop
1065 + //QV('DeskClip', debugmode); // Clipboard feature, not completed so show in in debug mode only.
1066 +
1067 + if (nightMode) { QC('body').add('night'); }
1068 + toggleFullScreen();
1069 +
1070 + // Setup page visuals
1071 + if (args.hide) {
1072 + var hide = parseInt(args.hide);
1073 + QV('masthead', !(hide & 1));
1074 + QV('topbar', !(hide & 2));
1075 + QV('footer', !(hide & 4));
1076 + QV('p10title', !(hide & 8));
1077 + QV('p11title', !(hide & 8));
1078 + QV('p12title', !(hide & 8));
1079 + QV('p13title', !(hide & 8));
1080 + QV('p14title', !(hide & 8));
1081 + QV('p15title', !(hide & 8));
1082 + QV('p16title', !(hide & 8));
1083 + //if (hide & 16) {
1084 + // QV('page_leftbar', false);
1085 + // QS('page_content').left = '0px';
1086 + //}
1087 +
1088 + // Fix the main grid to zero-height elements we want to hide.
1089 + QS('container')['grid-template-rows'] = ((hide & 1) ? '0' : '66') + 'px ' + ((hide & 2) ? '0' : '24') + 'px auto ' + ((hide & 4) ? '0' : '45') + 'px';
1090 + QS('container')['-ms-grid-rows'] = ((hide & 1) ? '0' : '66') + 'px ' + ((hide & 2) ? '0' : '24') + 'px auto ' + ((hide & 4) ? '0' : '45') + 'px';
1091 +
1092 + // Adjust height of remote desktop, files and Intel AMT
1093 + var xh = (((hide & 1) ? 0 : 66) + ((hide & 2) ? 0 : 24) + ((hide & 4) ? 0 : 45) + ((hide & 8) ? 0 : 60)); // 0 to 195
1094 + QS('p3users')['max-height'] = 'calc(100vh - ' + (124 + xh) + 'px)';
1095 + QS('p3events')['height'] = 'calc(100vh - ' + (124 + xh) + 'px)';
1096 + QS('deskarea3x')['height'] = 'calc(100vh - ' + (75 + xh) + 'px)';
1097 + QS('deskarea3x')['max-height'] = 'calc(100vh - ' + (75 + xh) + 'px)';
1098 + QS('p5filetable')['height'] = 'calc(100vh - ' + (160 + xh) + 'px)';
1099 + QS('p13filetable')['height'] = 'calc(100vh - ' + (124 + xh) + 'px)';
1100 + QS('serverMainStats')['height'] = 'calc(100vh - ' + (110 + xh) + 'px)';
1101 + QS('serverMainStats')['max-height'] = 'calc(100vh - ' + (110 + xh) + 'px)';
1102 + QS('xdevices')['max-height'] = 'calc(100vh - ' + (124 + xh) + 'px)';
1103 + QS('xdevicesmap')['max-height'] = 'calc(100vh - ' + (124 + xh) + 'px)';
1104 + QS('p15agentConsole')['height'] = 'calc(100vh - ' + (84 + xh) + 'px)';
1105 + QS('p15agentConsole')['max-height'] = 'calc(100vh - ' + (84 + xh) + 'px)';
1106 + QS('p15agentConsoleText')['height'] = 'calc(100vh - ' + (81 + xh) + 'px)';
1107 + QS('p15agentConsoleText')['max-height'] = 'calc(100vh - ' + (81 + xh) + 'px)';
1108 + }
1109 +
1110 + // We are looking at a single device, remove all the back buttons
1111 + if ('{{currentNode}}' != '') {
1112 + QV('p10BackButton', false);
1113 + QV('p11BackButton', false);
1114 + QV('p12BackButton', false);
1115 + QV('p13BackButton', false);
1116 + QV('p14BackButton', false);
1117 + QV('p15BackButton', false);
1118 + QV('p16BackButton', false);
1119 + }
1120 + p1updateInfo();
1121 +
1122 + // Setup the context menu
1123 + document.onclick = function (e) { hideContextMenu(); }
1124 + document.onkeypress = ondockeypress;
1125 + document.onkeydown = ondockeydown;
1126 + document.onkeyup = ondockeyup;
1127 + //window.addEventListener('focus', ondocfocus, false);
1128 + window.addEventListener('blur', ondocblur, false);
1129 + window.onresize = function () { masterUpdate(512); }
1130 + setTimeout(function() { masterUpdate(512); }, 200);
1131 +
1132 + // Connect to the mesh server
1133 + meshserver = MeshServerCreateControl(domainUrl, authCookie);
1134 + meshserver.onStateChanged = onStateChanged;
1135 + meshserver.onMessage = onMessage;
1136 + meshserver.trace = (args.trace == 1);
1137 + meshserver.Start();
1138 +
1139 + // Setup page controls
1140 + Q('sortselect').selectedIndex = sort = getstore('sort', 0);
1141 + Q('sizeselect').selectedIndex = getstore('_viewsize', 1);
1142 + Q('SearchInput').value = getstore('_search', '');
1143 + showRealNames = (getstore('showRealNames', 0) == 1);
1144 + Q('RealNameCheckBox').checked = showRealNames;
1145 + Q('viewselect').value = getstore('_deviceView', 1);
1146 + Q('DeskControl').checked = (getstore('DeskControl', 1) == 1);
1147 + QV('accountChangeEmailAddressSpan', (features & 0x200000) == 0);
1148 +
1149 + // Display the page devices
1150 + masterUpdate(3)
1151 + for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
1152 + Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
1153 +
1154 + // Setup upload drag & drop
1155 + Q('p5filetable').addEventListener('drop', p5fileDragDrop, false);
1156 + Q('p5filetable').addEventListener('dragover', p5fileDragOver, false);
1157 + Q('p5filetable').addEventListener('dragleave', p5fileDragLeave, false);
1158 + //Q('p5fileCatchAllInput').addEventListener('drop', p5fileDragDrop, false);
1159 + //Q('p5fileCatchAllInput').addEventListener('dragover', p5fileDragOver, false);
1160 + //Q('p5fileCatchAllInput').addEventListener('dragleave', p5fileDragLeave, false);
1161 +
1162 + // Setup upload drag & drop
1163 + Q('p13filetable').addEventListener('drop', p13fileDragDrop, false);
1164 + Q('p13filetable').addEventListener('dragover', p13fileDragOver, false);
1165 + Q('p13filetable').addEventListener('dragleave', p13fileDragLeave, false);
1166 +
1167 + // Timeline update interval
1168 + setInterval(updateDeviceTimeline, 120000); // Check every 2 minutes
1169 +
1170 + // Load desktop settings
1171 + var t = localStorage.getItem('desktopsettings');
1172 + if (t != null) { desktopsettings = JSON.parse(t); }
1173 + t = localStorage.getItem('multidesktopsettings');
1174 + if (t != null) { multidesktopsettings = JSON.parse(t); }
1175 + applyDesktopSettings();
1176 +
1177 + // Terminal special keys
1178 + var x = '';
1179 + for (var c = 1; c < 27; c++) x += '<option value=\'' + c + '\'>' + "Ctrl" + '-' + String.fromCharCode(64 + c) + ' (' + c + ')</option>';
1180 + QH('specialkeylist', x);
1181 +
1182 + // Setup server stats panels
1183 + setupGeneralServerStats();
1184 + setupServerTimelineStats();
1185 +
1186 + // Setup the user interface in the right mode
1187 + userInterfaceSelectMenu();
1188 +
1189 + // If SSPI or LDAP authentication not used, allow batch account creation.
1190 + QV('p4UserBatchCreate', (features & 0x00080000) == 0);
1191 + }
1192 +
1193 + // Toggle the web page to full screen
1194 + function toggleAspectRatio(toggle) {
1195 + if (toggle === 1) { deskAspectRatio = ((deskAspectRatio + 1) % 3); putstore('deskAspectRatio', deskAspectRatio); }
1196 + deskAdjust();
1197 + }
1198 +
1199 + // If FullScreen, toggle menu to be horisontal or vertical
1200 + function toggleStackMenu(toggle) {
1201 + if (webPageFullScreen == true) {
1202 + if (toggle === 1) {
1203 + webPageStackMenu = !webPageStackMenu;
1204 + putstore('webPageStackMenu', webPageStackMenu);
1205 + }
1206 + if (webPageStackMenu == false) {
1207 + QC('body').remove('menu_stack');
1208 + } else {
1209 + QC('body').add('menu_stack');
1210 + if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
1211 + }
1212 + deskAdjust();
1213 + }
1214 + }
1215 +
1216 + // Toggle user interface menu
1217 + function showUserInterfaceSelectMenu() {
1218 + Q('uiViewButton1').classList.remove('uiSelectorSel');
1219 + Q('uiViewButton2').classList.remove('uiSelectorSel');
1220 + Q('uiViewButton3').classList.remove('uiSelectorSel');
1221 + Q('uiViewButton4').classList.remove('uiSelectorSel');
1222 + try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
1223 + QV('uiMenu', (QS('uiMenu').display == 'none'));
1224 + //Q('uiViewButton1').focus();
1225 + if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
1226 + }
1227 +
1228 + function userInterfaceSelectMenu(s) {
1229 + if (s) { uiMode = s; putstore('uiMode', uiMode); }
1230 + webPageFullScreen = (uiMode < 3);
1231 + webPageStackMenu = (uiMode > 1);
1232 + toggleFullScreen(0);
1233 + toggleStackMenu(0);
1234 + if (webPageStackMenu && (xxcurrentView >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
1235 + }
1236 +
1237 + function toggleNightMode() {
1238 + nightMode = !nightMode;
1239 + if (nightMode) { QC('body').add('night'); } else { QC('body').remove('night'); }
1240 + putstore('_nightMode', nightMode?'1':'0');
1241 + }
1242 +
1243 + // Toggle the web page to full screen
1244 + function toggleFullScreen(toggle) {
1245 + if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
1246 + var hide = 0;
1247 + if (args.hide) { hide = parseInt(args.hide); }
1248 + if (webPageFullScreen == false) {
1249 + QC('body').remove('menu_stack');
1250 + QC('body').remove('fullscreen');
1251 + QC('body').remove('arg_hide');
1252 + if (xxcurrentView >= 10) QC('column_l').add('room4submenu');
1253 + QV('UserDummyMenuSpan', false);
1254 + //QV('page_leftbar', false);
1255 + } else {
1256 + QC('body').add('fullscreen');
1257 + if (hide & 16) QC('body').add('arg_hide'); // This is replacement for QV('page_leftbar', !(hide & 16));
1258 + QV('page_leftbar', !(hide & 16));
1259 + QV('MainMenuSpan', !(hide & 16));
1260 + if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
1261 + QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
1262 + }
1263 + masterUpdate(512);
1264 + QV('body', true);
1265 + }
1266 +
1267 + function getNodeFromId(id) { if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } } return null; }
1268 + function reload() {
1269 + var x = window.location.href;
1270 + if (x.endsWith('/#')) { x = x.substring(0, x.length - 2); }
1271 + window.location.href = x;
1272 + }
1273 +
1274 + function onStateChanged(server, state, prevState, errorCode) {
1275 + if (state == 0) {
1276 + // Control web socket disconnected
1277 + setDialogMode(0); // Close any dialog boxes if present
1278 + go(0); // Go to disconnection panel
1279 +
1280 + // Clean up
1281 + powerTimeline = null;
1282 + powerTimelineReq = null;
1283 + powerTimelineNode = null;
1284 + powerTimelineUpdate = null;
1285 + deleteAllNotifications(); // Close and clear notifications if present
1286 + hideContextMenu(); // Hide the context menu if present
1287 + QV('verifyEmailId2', false);
1288 + QV('logoutControl', false);
1289 + if (errorCode == 'noauth') { QH('p0span', "Unable to perform authentication"); return; }
1290 + if (prevState == 2) { if (autoReconnect) { setTimeout(serverPoll, 5000); } } else { QH('p0span', "Unable to connect web socket"); }
1291 + if (authCookieRenewTimer != null) { clearInterval(authCookieRenewTimer); authCookieRenewTimer = null; }
1292 + } else if (state == 2) {
1293 + // Fetch list of meshes, nodes, files
1294 + meshserver.send({ action: 'meshes' });
1295 + meshserver.send({ action: 'nodes', id: '{{currentNode}}' });
1296 + if ('{{currentNode}}' == '') { meshserver.send({ action: 'files' }); }
1297 + if ('{{viewmode}}' == '') { go(1); }
1298 + authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
1299 + }
1300 + }
1301 +
1302 + // Poll the server, if it responds, refresh the page.
1303 + function serverPoll() {
1304 + var xdr = null;
1305 + try { xdr = new XDomainRequest(); } catch (e) { }
1306 + if (!xdr) xdr = new XMLHttpRequest();
1307 + xdr.open('HEAD', window.location.href);
1308 + xdr.timeout = 15000;
1309 + xdr.onload = function () { reload(); };
1310 + xdr.onerror = xdr.ontimeout = function () { setTimeout(serverPoll, 10000); };
1311 + xdr.send();
1312 + }
1313 +
1314 + // Return true if this browser supports clickonce
1315 + function detectClickOnce() {
1316 + for (var i in window.navigator.mimeTypes) { if (window.navigator.mimeTypes[i].type == 'application/x-ms-application') { return true; } }
1317 + var userAgent = window.navigator.userAgent.toUpperCase();
1318 + return (userAgent.indexOf('.NET CLR 3.5') >= 0) || (userAgent.indexOf('(WINDOWS NT ') >= 0);
1319 + }
1320 +
1321 + function updateSiteAdmin() {
1322 + var noServerBackup = '{{{noServerBackup}}}';
1323 + var siteRights = userinfo.siteadmin;
1324 + if (noServerBackup == 1) { siteRights &= 0xFFFFFFFA; } // If not server backups allowed, remove server backup and restore permissions
1325 +
1326 + // Update account actions
1327 + 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.
1328 + QV('p2AccountActions', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide Account Actions if in single user mode or domain authentication
1329 + QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel
1330 + QV('p2ServerActions', siteRights & 21);
1331 + QV('LeftMenuMyServer', siteRights & 21); // 16 + 4 + 1
1332 + QV('MainMenuMyServer', siteRights & 21);
1333 + QV('p2ServerActionsBackup', siteRights & 1);
1334 + QV('p2ServerActionsRestore', siteRights & 4);
1335 + QV('p2ServerActionsVersion', siteRights & 16);
1336 + QV('MainMenuMyFiles', siteRights & 8);
1337 + QV('LeftMenuMyFiles', siteRights & 8);
1338 + if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { setDialogMode(0); go(1); }
1339 + if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
1340 +
1341 + // Update user management state
1342 + if ((userinfo.siteadmin & 2) != 0)
1343 + {
1344 + // We are user administrator
1345 + if (users == null) { meshserver.send({ action: 'users' }); }
1346 + if (wssessions == null) { meshserver.send({ action: 'wssessioncount' }); }
1347 + } else {
1348 + // We are not user administrator
1349 + users = null;
1350 + wssessions = null;
1351 + updateUsers();
1352 + if (xxcurrentView == 4 || ((xxcurrentView >= 30) && (xxcurrentView < 40))) { setDialogMode(0); go(1); currentUser = null; }
1353 + }
1354 + meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
1355 + QV('ServerConsole', userinfo.siteadmin === 0xFFFFFFFF);
1356 + QV('ServerTrace', userinfo.siteadmin === 0xFFFFFFFF);
1357 + if ((xxcurrentView == 115) && (userinfo.siteadmin != 0xFFFFFFFF)) { go(6); }
1358 + if ((xxcurrentView == 6) && ((userinfo.siteadmin & 21) == 0)) { go(1); }
1359 +
1360 + // If we are site administrator, register to get server statistics
1361 + if ((siteRights & 21) != 0) { meshserver.send({ action: 'serverstats', interval: 10000 }); }
1362 + }
1363 +
1364 + // To boost the speed of the web page when even floods occur, this method perform a delayed update on the web page.
1365 + var updateNaggleTimer = null;
1366 + var updateNaggleFlags = 0;
1367 + function masterUpdate(flags) {
1368 + updateNaggleFlags |= flags;
1369 + if (updateNaggleTimer == null) {
1370 + updateNaggleTimer = setTimeout(function () {
1371 + if (updateNaggleFlags & 512) { center(); }
1372 + if (updateNaggleFlags & 1) { onSearchInputChanged(); }
1373 + if (updateNaggleFlags & 2) { onSortSelectChange(false); }
1374 + if (updateNaggleFlags & 128) { updateMeshes(); }
1375 + if (updateNaggleFlags & 4) { updateDevices(); }
1376 + if (updateNaggleFlags & 8) { drawNotifications(); }
1377 + if (updateNaggleFlags & 16) { updateMapMarkers(); }
1378 + if (updateNaggleFlags & 32) { eventsUpdate(); }
1379 + if (updateNaggleFlags & 64) { refreshMap(false, true); }
1380 + if (updateNaggleFlags & 256) { drawDeviceTimeline(); }
1381 + if (updateNaggleFlags & 1024) { deviceEventsUpdate(); }
1382 + if (updateNaggleFlags & 2048) { userEventsUpdate(); }
1383 + if (updateNaggleFlags & 4096) { p20updateMesh(); }
1384 + updateNaggleTimer = null;
1385 + updateNaggleFlags = 0;
1386 + }, 150);
1387 + }
1388 + }
1389 +
1390 + var backupCodesWarningDone = false;
1391 + function updateSelf() {
1392 + QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
1393 + QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
1394 + QV('manageOtp', (userinfo.otpsecret == 1) || (userinfo.otphkeys > 0));
1395 + QV('authAppSetupCheck', userinfo.otpsecret == 1);
1396 + QV('authKeySetupCheck', userinfo.otphkeys > 0);
1397 + QV('authCodesSetupCheck', userinfo.otpkeys > 0);
1398 + masterUpdate(4 + 128 + 4096);
1399 +
1400 + // Check if backup codes should really be enabled
1401 + if ((backupCodesWarningDone == false) && !(userinfo.otpkeys > 0) && (((userinfo.otpsecret == 1) && !(userinfo.otphkeys > 0)) || ((userinfo.otpsecret != 1) && (userinfo.otphkeys == 1)))) {
1402 + var n = { text: "Please add two-factor backup codes. If the current factor is lost, there is not way to recover this account.", title: "Two factor authentication" };
1403 + addNotification(n);
1404 + backupCodesWarningDone = true;
1405 + }
1406 +
1407 + // If we can't create new groups, hide all links that can do that.
1408 + var newGroupsAllowed = ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 64) == 0));
1409 + QV('p2createMeshLink1', newGroupsAllowed);
1410 + QV('p2createMeshLink2', newGroupsAllowed);
1411 + QV('getStarted1', newGroupsAllowed);
1412 + QV('getStarted2', !newGroupsAllowed);
1413 +
1414 + if (typeof userinfo.passchange == 'number') {
1415 + if (userinfo.passchange == -1) { QH('p2nextPasswordUpdateTime', "- Réinitialiser à la prochaine connexion."); }
1416 + else if ((passRequirements != null) && (typeof passRequirements.reset == 'number')) {
1417 + var seconds = (userinfo.passchange) + (passRequirements.reset * 86400) - Math.floor(Date.now() / 1000);
1418 + if (seconds < 0) { QH('p2nextPasswordUpdateTime', "- Réinitialiser à la prochaine connexion."); }
1419 + else if (seconds < 3600) { QH('p2nextPasswordUpdateTime', format("- Réinitialisation en {0} minute {1}.", Math.floor(seconds / 60), addLetterS(Math.floor(seconds / 60)))); }
1420 + else if (seconds < 86400) { QH('p2nextPasswordUpdateTime', format("- Réinitialisation dans {0} heure {1}.", Math.floor(seconds / 3600), addLetterS(Math.floor(seconds / 3600)))); }
1421 + else { QH('p2nextPasswordUpdateTime', format("- Réinitialiser dans le {0} jour {1}."), Math.floor(seconds / 86400), addLetterS(Math.floor(seconds / 86400))); }
1422 + }
1423 + }
1424 + }
1425 +
1426 + function addLetterS(x) { return (x > 1) ? 's' : ''; }
1427 + function setSessionActivity() { sessionActivity = Date.now(); QH('idleTimeoutNotify', ''); }
1428 + function checkIdleSessionTimeout() {
1429 + var delta = (Date.now() - sessionActivity);
1430 + if (delta > serverinfo.timeout) { window.location.href = 'logout'; } else {
1431 + var ds = Math.round((serverinfo.timeout - delta) / 1000);
1432 + if (ds <= 60) {
1433 + QH('idleTimeoutNotify', '<br />' + format("{0} second{1} until disconnect", ds, addLetterS(ds)));
1434 + } else {
1435 + ds = Math.round(ds / 60);
1436 + if (ds <= 5) { QH('idleTimeoutNotify', '<br />' + format("{0} minute{1} until disconnect", ds, addLetterS(ds))); }
1437 + }
1438 + }
1439 + }
1440 +
1441 + function onMessage(server, message) {
1442 + switch (message.action) {
1443 + case 'trace': {
1444 + serverTrace.unshift(message);
1445 + displayServerTrace();
1446 + break;
1447 + }
1448 + case 'traceinfo': {
1449 + if (typeof message.traceSources == 'object') {
1450 + if ((message.traceSources != null) && (message.traceSources.length > 0)) {
1451 + serverTraceSources = message.traceSources;
1452 + QH('p41traceStatus', EscapeHtml(message.traceSources.join(', ')));
1453 + } else {
1454 + serverTraceSources = [];
1455 + QH('p41traceStatus', "None");
1456 + }
1457 + }
1458 + break;
1459 + }
1460 + case 'serverstats': {
1461 + updateGeneralServerStats(message);
1462 + break;
1463 + }
1464 + case 'servertimelinestats': {
1465 + setServerTimelineStats(message.events);
1466 + break;
1467 + }
1468 + case 'authcookie': {
1469 + // Got an authentication cookie refresh
1470 + authCookie = message.cookie;
1471 + authRelayCookie = message.rcookie;
1472 + break;
1473 + }
1474 + case 'serverinfo': {
1475 + serverinfo = message.serverinfo;
1476 + if (serverinfo.timeout) { setInterval(checkIdleSessionTimeout, 10000); checkIdleSessionTimeout(); }
1477 + if (debugmode == 1) { console.log('Server time: ', printDateTime(new Date(serverinfo.serverTime))); }
1478 + break;
1479 + }
1480 + case 'userinfo': {
1481 + userinfo = message.userinfo;
1482 + updateSiteAdmin();
1483 + updateSelf();
1484 + break;
1485 + }
1486 + case 'users': {
1487 + users = {};
1488 + for (var m in message.users) { users[message.users[m]._id] = message.users[m]; }
1489 + updateUsers();
1490 + break;
1491 + }
1492 + case 'wssessioncount': {
1493 + wssessions = message.wssessions;
1494 + updateUsers();
1495 + break;
1496 + }
1497 + case 'meshes': {
1498 + meshes = {};
1499 + for (var m in message.meshes) { meshes[message.meshes[m]._id] = message.meshes[m]; }
1500 + masterUpdate(4 + 128);
1501 + break;
1502 + }
1503 + case 'files': {
1504 + filetree = setupBackPointers(message.filetree);
1505 + updateFiles();
1506 + d3updatefiles();
1507 + break;
1508 + }
1509 + case 'nodes': {
1510 + nodes = [];
1511 + for (var m in message.nodes) {
1512 + if (!meshes[m]) { console.log('Invalid mesh (1): ' + m); continue; }
1513 + for (var n in message.nodes[m]) {
1514 + if (message.nodes[m][n]._id == null) { console.log('Invalid node (' + n + '): ' + JSON.stringify(message.nodes)); continue; }
1515 + message.nodes[m][n].namel = message.nodes[m][n].name.toLowerCase();
1516 + 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; }
1517 + message.nodes[m][n].meshnamel = meshes[m].name.toLowerCase();
1518 + message.nodes[m][n].meshid = m;
1519 + message.nodes[m][n].state = (message.nodes[m][n].state)?(message.nodes[m][n].state):0;
1520 + message.nodes[m][n].desc = message.nodes[m][n].desc;
1521 + message.nodes[m][n].ip = message.nodes[m][n].ip;
1522 + if (!message.nodes[m][n].icon) message.nodes[m][n].icon = 1;
1523 + message.nodes[m][n].ident = ++nodeShortIdent;
1524 + nodes.push(message.nodes[m][n]);
1525 + }
1526 + }
1527 + masterUpdate(1 | 2 | 4 | 64);
1528 +
1529 + if (xxcurrentView == -1) { if ('{{viewmode}}' != '') { go(parseInt('{{viewmode}}')); } else { setDialogMode(0); go(1); } }
1530 + if ('{{currentNode}}' != '') { gotoDevice('{{currentNode}}',parseInt('{{viewmode}}'));}
1531 + break;
1532 + }
1533 + case 'powertimeline': {
1534 + if (message.nodeid != powerTimelineReq) break;
1535 + powerTimelineNode = message.nodeid;
1536 + powerTimeline = message.timeline;
1537 + powerTimelineUpdate = Date.now() + 300000; // Update every 5 minutes
1538 + for (var i in powerTimeline) { if (i % 2 == 1) { powerTimeline[i] = powerTimeline[i] * 1000; } } // Decompress time
1539 + if (currentNode._id == message.nodeid) { masterUpdate(256); }
1540 + break;
1541 + }
1542 + case 'getsysinfo': {
1543 + if (message.nodeid != powerTimelineReq) break;
1544 + //console.log('getsysinfo', message); // ***********************
1545 + if (message.noinfo === true) {
1546 + QH('p17info', "No information for this device.");
1547 + } else {
1548 + var x = '', s = {};
1549 + if (message.hardware) {
1550 + if (message.hardware.identifiers) {
1551 + var ident = message.hardware.identifiers;
1552 + // BIOS
1553 + x += '<div class=DevSt style=margin-bottom:3px><b>' + "BIOS" + '</b></div>';
1554 + if (ident.bios_vendor) { x += addDetailItem("Vendor", ident.bios_vendor, s); }
1555 + if (ident.bios_version) { x += addDetailItem("Version", ident.bios_version, s); }
1556 + x += '<br />';
1557 +
1558 + // Motherboard
1559 + x += '<div class=DevSt style=margin-bottom:3px><b>' + "Motherboard" + '</b></div>';
1560 + if (ident.board_vendor) { x += addDetailItem("Vendor", ident.board_vendor, s); }
1561 + if (ident.board_name) { x += addDetailItem("Name", ident.board_name, s); }
1562 + if (ident.board_serial && (ident.board_serial != '')) { x += addDetailItem("Serial", ident.board_serial, s); }
1563 + if (ident.board_version) { x += addDetailItem("Version", ident.board_version, s); }
1564 + if (ident.product_uuid) { x += addDetailItem("Identifier", ident.product_uuid, s); }
1565 + x += '<br />';
1566 + }
1567 +
1568 + if (message.hardware.windows) {
1569 + if (message.hardware.windows.memory) {
1570 + // Memory
1571 + x += '<div class=DevSt style=margin-bottom:3px><b>' + "Memory" + '</b></div>';
1572 +
1573 + // Sort Memory
1574 + function memorySort(a, b) { if (a.BankLabel > b.BankLabel) return 1; if (a.BankLabel < b.BankLabel) return -1; return 0; }
1575 + message.hardware.windows.memory.sort(memorySort);
1576 +
1577 + x += '<table style=width:100%>';
1578 + for (var i in message.hardware.windows.memory) {
1579 + var m = message.hardware.windows.memory[i];
1580 + x += '<tr><td VALIGN=Top style=width:38px><img src="images/ram2.png" />'
1581 + x += '<td><div style=background-color:lightgray;border-radius:5px;padding:8px>';
1582 + x += '<div><b>' + m.BankLabel + '</b></div>';
1583 + if (m.Capacity) { x += addDetailItem("Capacity / Speed", format("{0} Mb, {1} Mhz", (m.Capacity / 1024 / 1024), m.Speed), s); }
1584 + if (m.PartNumber) { x += addDetailItem("Part Number", ((m.Manufacturer && m.Manufacturer != 'Undefined')?(m.Manufacturer + ', '):'') + m.PartNumber, s); }
1585 + x += '</div>';
1586 + }
1587 + x += '</table><br />';
1588 + }
1589 +
1590 + if (message.hardware.windows.osinfo) {
1591 + // Operating System
1592 + var m = message.hardware.windows.osinfo;
1593 + x += '<div class=DevSt style=margin-bottom:3px><b>' + "Operating System" + '</b></div>';
1594 + if (m.Caption) { x += addDetailItem("Name", m.Caption, s); }
1595 + if (m.Version) { x += addDetailItem("Version", m.Version, s); }
1596 + if (m.OSArchitecture) { x += addDetailItem("Architecture", m.OSArchitecture, s); }
1597 + x += '<br />';
1598 + }
1599 +
1600 + // Disks
1601 + //x += '<div class=DevSt style=margin-bottom:3px><b>Disks</b></div>';
1602 + //x += '<br />';
1603 + }
1604 + }
1605 +
1606 + QH('p17info', x);
1607 + }
1608 + break;
1609 + }
1610 + case 'lastconnect': {
1611 + var node = getNodeFromId(message.nodeid);
1612 + if (node != null) {
1613 + node.lastconnect = message.time;
1614 + node.lastaddr = message.addr;
1615 + if ((currentNode._id == node._id) && (Q('MainComputerState').innerHTML == '')) {
1616 + QH('MainComputerState', '<span>' + "Last seen:" + '<br />' + printDateTime(new Date(node.lastconnect)) + '</span>');
1617 + }
1618 + }
1619 + break;
1620 + }
1621 + case 'msg': {
1622 + // Check if this is a message from a node
1623 + if (message.nodeid != null) {
1624 + var index = -1;
1625 + if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == message.nodeid) { index = i; break; } } }
1626 + if (index != -1) {
1627 + // Node was found, dispatch the message
1628 + if (message.type == 'console') { p15consoleReceive(nodes[index], message.value, message.source); } // This is a console message.
1629 + else if (message.type == 'notify') { // This is a notification message.
1630 + var n = getstore('notifications', 0);
1631 + if (((n & 8) == 0) && (message.amtMessage != null)) { break; } // Intel AMT desktop & terminal messages should be ignored.
1632 + var n = { text: message.value, title: message.title, icon: message.icon };
1633 + if (message.nodeid != null) { n.nodeid = message.nodeid; }
1634 + if (message.tag != null) { n.tag = message.tag; }
1635 + if (message.username != null) { n.username = message.username; }
1636 + addNotification(n);
1637 + } else if (message.type == 'ps') {
1638 + showDeskToolsProcesses(message);
1639 + } else if (message.type == 'services') {
1640 + showDeskToolsServices(message);
1641 + } else if ((message.type == 'getclip') && (xxdialogTag == 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
1642 + Q('d2clipText').value = message.data;
1643 + } else if ((message.type == 'setclip') && (xxdialogTag == 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
1644 + // Display success/fail on the clipboard dialog box.
1645 + QH('dlgClipStatus', message.success ? '<span style=color:green>' + "Succès" + '</span>' : '<span style=color:red>' + "Failed" + '</span>')
1646 + setTimeout(function () { try { QH('dlgClipStatus', ''); } catch (ex) { } }, 2000);
1647 + }
1648 + }
1649 + } else {
1650 + if (message.type == 'notify') { // This is a notification message.
1651 + var n = { text: message.value, title: message.title, icon: message.icon };
1652 + if (message.tag != null) { n.tag = message.tag; }
1653 + if (message.username != null) { n.username = message.username; }
1654 + addNotification(n);
1655 + }
1656 + }
1657 + break;
1658 + }
1659 + case 'getnetworkinfo': {
1660 + if ((currentNode._id == message.nodeid) && (xxdialogMode == 2) && (xxdialogTag == 'if' + message.nodeid)) {
1661 + if (message.netif == null) {
1662 + QH('d2netinfo', "No network interface information available for this device.");
1663 + } else {
1664 + var x = '<div class=dialogText>';
1665 +
1666 + if (currentNode.lastconnect) { x += addHtmlValue2("Last agent connection", printDateTime(new Date(currentNode.lastconnect))); }
1667 + if (currentNode.lastaddr) {
1668 + var splitip = currentNode.lastaddr.split(':');
1669 + if (splitip.length > 2) {
1670 + // IPv6
1671 + x += addHtmlValue2("Last agent address", currentNode.lastaddr + ' <img src="images/link4.png" title="Copy address to clipboard" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(currentNode.lastaddr) + '\") width=10 height=10>');
1672 + } else {
1673 + // IPv4
1674 + if (isPrivateIP(currentNode.lastaddr)) {
1675 + x += addHtmlValue2("Last agent address", splitip[0] + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(splitip[0]) + '\") width=10 height=10>');
1676 + } else {
1677 + x += addHtmlValue2("Last agent address", '<a href="https://iplocation.com/?ip=' + splitip[0] + '" rel="noreferrer noopener" target="MeshIPLoopup">' + splitip[0] + '</a> <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(splitip[0]) + '\") width=10 height=10>');
1678 + }
1679 + }
1680 + }
1681 +
1682 + x += addHtmlValue2("Last interfaces update", printDateTime(new Date(message.updateTime)));
1683 + for (var i in message.netif) {
1684 + var net = message.netif[i];
1685 + x += '<hr />'
1686 + if (net.name) { x += addHtmlValue2("Name", '<b>' + EscapeHtml(net.name) + '</b>'); }
1687 + if (net.desc) { x += addHtmlValue2("Description", EscapeHtml(net.desc).replace('(R)', '&reg;').replace('(r)', '&reg;')); }
1688 + if (net.dnssuffix) { x += addHtmlValue2("DNS suffix", EscapeHtml(net.dnssuffix) + ' <img src="images/link4.png" title="' + "Copy name to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.dnssuffix) + '\") width=10 height=10>'); }
1689 + 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> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.mac.toLowerCase()) + '\") width=10 height=10>'); }
1690 + if (net.v4addr) { x += addHtmlValue2("IPv4 address", EscapeHtml(net.v4addr) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.v4addr) + '\") width=10 height=10>'); }
1691 + if (net.v4mask) { x += addHtmlValue2("IPv4 mask", EscapeHtml(net.v4mask) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.v4mask) + '\") width=10 height=10>'); }
1692 + if (net.v4gateway) { x += addHtmlValue2("IPv4 gateway", EscapeHtml(net.v4gateway) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.v4gateway) + '\") width=10 height=10>'); }
1693 + 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> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2(\"' + encodeURIComponent(net.gatewaymac.toLowerCase()) + '\") width=10 height=10>'); }
1694 + }
1695 + x += '</div>';
1696 + QH('d2netinfo', x);
1697 + }
1698 + }
1699 + break;
1700 + }
1701 + case 'serverversion': {
1702 + if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerUpdate')) {
1703 + var x = '<div class=dialogText>';
1704 + if (!message.current) { message.current = "Inconnue"; }
1705 + if (!message.latest) { message.latest = "Inconnue"; }
1706 + x += addHtmlValue2("Current Version", '<b>' + EscapeHtml(message.current) + '</b>');
1707 + x += addHtmlValue2("Latest Version", '<b>' + EscapeHtml(message.latest) + '</b>');
1708 + x += '</div>';
1709 + if ((message.latest.indexOf('.') == -1) || (message.current == message.latest) || ((features & 2048) == 0)) {
1710 + setDialogMode(2, "MeshCentral Version", 1, null, x);
1711 + } else {
1712 + 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>');
1713 + server_showVersionDlgUpdate();
1714 + }
1715 + }
1716 + break;
1717 + }
1718 + case 'servererrors': {
1719 + if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerErrors')) {
1720 + if (message.data == null) {
1721 + setDialogMode(2, "MeshCentral Server Errors", 1, null, "Server has no error log.");
1722 + } else {
1723 + var x = '<div class="dialogText dialogTextLog"><pre id=d2ServerErrorsLogPre>' + message.data + '<pre></div>';
1724 + 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>');
1725 + server_showVersionDlgUpdate();
1726 + }
1727 + }
1728 + break;
1729 + }
1730 + case 'serverconsole': {
1731 + p15consoleReceive('serverconsole', message.value);
1732 + break;
1733 + }
1734 + case 'events': {
1735 + if ((message.nodeid != null) && (message.nodeid == currentNode._id)) {
1736 + currentDeviceEvents = message.events;
1737 + masterUpdate(1024);
1738 + } else if ((message.user != null) && (message.user == currentUser.name)) {
1739 + currentUserEvents = message.events;
1740 + masterUpdate(2048);
1741 + } else {
1742 + events = message.events;
1743 + masterUpdate(32);
1744 + }
1745 + break;
1746 + }
1747 + case 'getcookie': {
1748 + if (message.tag == 'clickonce') {
1749 + var basicPort = '{{{serverRedirPort}}}' == '' ? '{{{serverPublicPort}}}' : '{{{serverRedirPort}}}';
1750 + 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');
1751 + var newWindow = window.open(rdpurl, '_blank');
1752 + newWindow.opener = null;
1753 + }
1754 + break;
1755 + }
1756 + case 'getNotes': {
1757 + var n = Q('d2devNotes');
1758 + if (n && (message.id == decodeURIComponent(n.attributes['noteid'].value))) {
1759 + if (message.notes) { QH('d2devNotes', decodeURIComponent(message.notes)); } else { QH('d2devNotes', ''); }
1760 + var ro = (n.attributes['ro'].value == 'true');
1761 + if (ro == false) { // If we have permissions, set read/write on this note.
1762 + n.removeAttribute('readonly');
1763 + QE('idx_dlgOkButton', true);
1764 + QV('idx_dlgOkButton', true);
1765 + focusTextBox('d2devNotes');
1766 + }
1767 + }
1768 + break;
1769 + }
1770 + case 'otpauth-request': {
1771 + if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-request')) {
1772 + var secret = message.secret;
1773 + if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); }
1774 + else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '<br/>' + secret.substring(20) }
1775 + 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>');
1776 + new QRCode(Q('qrcode'), { text: message.url, width: 128, height: 128, colorDark: '#000000', colorLight: '#EEE', correctLevel: QRCode.CorrectLevel.H });
1777 + QV('idx_dlgOkButton', true);
1778 + QE('idx_dlgOkButton', false);
1779 + Q('d2otpauthinput').focus();
1780 + }
1781 + break;
1782 + }
1783 + case 'otpauth-setup': {
1784 + if (xxdialogMode) return;
1785 + 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."));
1786 + break;
1787 + }
1788 + case 'otpauth-clear': {
1789 + if (xxdialogMode) return;
1790 + 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."));
1791 + break;
1792 + }
1793 + case 'otpauth-getpasswords': {
1794 + if (xxdialogMode) return;
1795 + var x = "One time tokens can be used as secondary authentication. Generate a set, print them and keep them in a safe place.";
1796 + 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 class=selecttext style=width:100%;text-align:center>';
1797 + if (message.passwords) {
1798 + var j = 0, clipb = '';
1799 + for (var i in message.passwords) {
1800 + if (++j % 2) { x += '<tr>'; }
1801 + var p = '' + message.passwords[i].p;
1802 + while (p.length < 8) { p = '0' + p; }
1803 + if (message.passwords[i].u === true) {
1804 + x += '<td>' + p.substring(0, 4) + '&nbsp;' + p.substring(4);
1805 + if (clipb != '') { clipb += ' '; }
1806 + clipb += p;
1807 + } else {
1808 + x += '<td><strike style=color:#BBB>' + p.substring(0, 4) + '&nbsp;' + p.substring(4); + '</strike>';
1809 + }
1810 + }
1811 + } else {
1812 + x += '<tr><td>' + "No Active Tokens";
1813 + }
1814 + x += '</table></div></div><br />';
1815 + x += '<div><input type=button value=' + "Close" + ' onclick=setDialogMode(0) style=float:right></input>';
1816 + x += '<input type=button value="' + "Generate New Tokens" + '" onclick="account_manageOtp(1);"></input>';
1817 + if (message.passwords != null) {
1818 + x += '<input type=button value="' + "Clear Tokens" + '" onclick="account_manageOtp(2);"></input>';
1819 + x += '&nbsp;<img src=images/link4.png height=10 width=10 title="' + "Copy valid codes to clipboard" + '" style=cursor:pointer onclick=copyTextToClip2("' + encodeURIComponent(clipb) + '")>';
1820 + }
1821 + x += '</div><br />';
1822 + setDialogMode(2, "Manage Backup Codes", 8, null, x, 'otpauth-manage');
1823 + break;
1824 + }
1825 + case 'otp-hkey-get': {
1826 + if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
1827 + 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>';
1828 + var end = '</table></div></div>';
1829 + var x = "<a href=\"https://www.yubico.com/\" rel=\"noreferrer noopener\" target=\"_blank\">Hardware keys</a> are used as secondary login authentication.";
1830 + x += '<div style="max-height:150px;overflow-y:auto;overflow-x:hidden;margin-top:6px;margin-bottom:6px">';
1831 + if (message.keys && message.keys.length > 0) {
1832 + for (var i in message.keys) {
1833 + var key = message.keys[i], type = (key.type == 2)?'OTP':'WebAuthn';
1834 + 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;
1835 + }
1836 + } else {
1837 + x += start + '<tr style=text-align:center><td>' + "No Keys Configured" + end;
1838 + }
1839 + x += '</div>';
1840 + x += '<div><input type=button value="' + "Close" + '" onclick=setDialogMode(0) style=float:right></input>';
1841 + if ((features & 0x00020000) != 0) { x += '<input id=d2addkey3 type=button value="' + "Add Key" + '" onclick="account_addhkey(3);"></input>'; }
1842 + if ((features & 0x00004000) != 0) { x += '<input id=d2addkey2 type=button value="' + "Add YubiKey&reg; OTP" + '" onclick="account_addhkey(2);"></input>'; }
1843 + x += '</div><br />';
1844 + setDialogMode(2, "Manage Security Keys", 8, null, x, 'otpauth-hardware-manage');
1845 + if (u2fSupported() == false) { QE('d2addkey1', false); }
1846 + break;
1847 + }
1848 + case 'otp-hkey-yubikey-add': {
1849 + if (message.result) {
1850 + meshserver.send({ action: 'otp-hkey-get' }); // Success, ask for the full list of keys.
1851 + } else {
1852 + setDialogMode(2, "Ajouter une clé de sécurité", 1, null, '<br />' + "Error, Unable to add key." + '<br /><br />');
1853 + }
1854 + break;
1855 + }
1856 + case 'otp-hkey-setup-response': {
1857 + if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
1858 + if (message.result == true) {
1859 + meshserver.send({ action: 'otp-hkey-get' }); // Success, ask for the full list of keys.
1860 + } else {
1861 + setDialogMode(2, "Ajouter une clé de sécurité", 1, null, '<br />' + "ERROR: Unable to add key." + '<br /><br />', 'otpauth-hardware-manage');
1862 + }
1863 + break;
1864 + }
1865 + case 'webauthn-startregister': {
1866 + if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
1867 + 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 + ' />';
1868 + setDialogMode(2, "Ajouter une clé de sécurité", 2, null, x);
1869 +
1870 + var publicKey = message.request;
1871 + message.request.challenge = Uint8Array.from(atob(message.request.challenge), function (c) { return c.charCodeAt(0) })
1872 + message.request.user.id = Uint8Array.from(atob(message.request.user.id), function (c) { return c.charCodeAt(0) })
1873 + navigator.credentials.create({ publicKey: publicKey })
1874 + .then(function(newCredentialInfo) {
1875 + // Public key credential
1876 + 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 };
1877 + meshserver.send({ action: 'webauthn-endregister', response: r });
1878 + setDialogMode(0);
1879 + }, function(error) {
1880 + // Error
1881 + setDialogMode(2, "Ajouter une clé de sécurité", 1, null, "ERROR: " + error);
1882 + });
1883 + break;
1884 + }
1885 + case 'event': {
1886 + if (!message.event.nolog) {
1887 + if (currentNode && (message.event.nodeid == currentNode._id)) {
1888 + // If this event has a nodeid and we are looking at this node, update the log in real time.
1889 + currentDeviceEvents.unshift(message.event);
1890 + var eventLimit = parseInt(p16limitdropdown.value);
1891 + while (currentDeviceEvents.length > eventLimit) { currentDeviceEvents.pop(); } // Remove element(s) at the end
1892 + masterUpdate(1024);
1893 + }
1894 +
1895 + if (currentUser && (message.event.userid == currentUser._id)) {
1896 + // If this event has a userid and we are looking at this user, update the log in real time.
1897 + currentUserEvents.unshift(message.event);
1898 + var eventLimit = parseInt(p31limitdropdown.value);
1899 + while (currentUserEvents.length > eventLimit) { currentUserEvents.pop(); } // Remove element(s) at the end
1900 + masterUpdate(2048);
1901 + }
1902 +
1903 + // Add this event to the master events log.
1904 + events.unshift(message.event);
1905 + var eventLimit = parseInt(p3limitdropdown.value);
1906 + while (events.length > eventLimit) { events.pop(); } // Remove element(s) at the end
1907 + masterUpdate(32);
1908 + }
1909 + if (message.event.noact) break; // Take no action on this event
1910 + switch (message.event.action) {
1911 + case 'userWebState': {
1912 + // New user web state, update the web page as needed
1913 + if (localStorage != null) {
1914 + var oldShowRealNames = localStorage.getItem('showRealNames');
1915 + var oldUiMode = localStorage.getItem('uiMode');
1916 + var oldSort = localStorage.getItem('sort');
1917 + var oldLoctag = localStorage.getItem('loctag');
1918 +
1919 + var webstate = JSON.parse(message.event.state);
1920 + for (var i in webstate) { localStorage.setItem(i, webstate[i]); }
1921 +
1922 + // Update the web page
1923 + if ((webstate.deskAspectRatio != null) && (webstate.deskAspectRatio != deskAspectRatio)) { deskAspectRatio = webstate.deskAspectRatio; deskAdjust(); }
1924 + if ((webstate.showRealNames != null) && (webstate.showRealNames != oldShowRealNames)) { showRealNames = Q('RealNameCheckBox').checked = (webstate.showRealNames == '1'); masterUpdate(6); }
1925 + if ((webstate.uiMode != null) && (webstate.uiMode != oldUiMode)) { userInterfaceSelectMenu(parseInt(webstate.uiMode)); }
1926 + if ((webstate.sort != null) && (webstate.sort != oldSort)) { document.getElementById('sortselect').selectedIndex = sort = parseInt(webstate.sort); masterUpdate(6); }
1927 + if ((webstate.loctag != null) && (webstate.loctag != oldLoctag)) { if (webstate.loctag != null) { args.locale = webstate.loctag; } else { delete args.locale; } masterUpdate(0xFFFFFFFF); }
1928 + }
1929 + break;
1930 + }
1931 + case 'servertimelinestats': { addServerTimelineStats(message.event.data); break; }
1932 + case 'accountcreate':
1933 + case 'accountchange': {
1934 + // An account was created or changed
1935 + if (userinfo.name == message.event.account.name) {
1936 + var newsiteadmin = message.event.account.siteadmin?message.event.account.siteadmin:0;
1937 + var oldsiteadmin = userinfo.siteadmin?userinfo.siteadmin:0;
1938 + if ((message.event.account.quota != userinfo.quota) || (((userinfo.siteadmin & 8) == 0) && ((message.event.account.siteadmin & 8) != 0))) { meshserver.send({ action: 'files' }); }
1939 + var oldgroups = userinfo.groups;
1940 + userinfo = message.event.account;
1941 + if (oldsiteadmin != newsiteadmin) updateSiteAdmin();
1942 + updateSelf();
1943 +
1944 + if ((userinfo.siteadmin & 2) != 0) {
1945 + // Compare our groups
1946 + var og = oldgroups ? oldgroups : [];
1947 + var ng = userinfo.groups ? userinfo.groups : [];
1948 + if (og.join(',') != ng.join(',')) {
1949 + // Our groups have changed, re-ask for a list of users.
1950 + users = wssessions = null;
1951 + meshserver.send({ action: 'users' });
1952 + meshserver.send({ action: 'wssessioncount' });
1953 + }
1954 + }
1955 + }
1956 + if (users == null) break;
1957 +
1958 + // Check if the account is part of our user group
1959 + if ((userinfo.groups == null) || (userinfo.groups.length == 0) || (findOne(message.event.account.groups, userinfo.groups) == true)) {
1960 + users[message.event.account._id] = message.event.account; // Part of our groups, update this user.
1961 + } else {
1962 + delete users[message.event.account._id]; // No longer part of our groups, remove this user.
1963 + }
1964 +
1965 + updateUsers();
1966 + break;
1967 + }
1968 + case 'accountremove': {
1969 + // An account was removed
1970 + if (users == null) break;
1971 + delete users['user/' + domain + '/' + message.event.username.toLowerCase()];
1972 + updateUsers();
1973 + break;
1974 + }
1975 + case 'createmesh': {
1976 + // A new mesh was created
1977 + 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.
1978 + meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
1979 + masterUpdate(4 + 128);
1980 + meshserver.send({ action: 'files' });
1981 + }
1982 + break;
1983 + }
1984 + case 'meshchange': {
1985 + // Update mesh information
1986 + if (meshes[message.event.meshid] == null) {
1987 + // This is a new mesh for us
1988 + meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
1989 + meshserver.send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh).
1990 + } else {
1991 + // This is an existing mesh
1992 + if (message.event.name != null) {
1993 + meshes[message.event.meshid].name = message.event.name;
1994 + for (var i in nodes) { if (nodes[i].meshid == message.event.meshid) { nodes[i].meshnamel = message.event.name.toLowerCase(); } }
1995 + }
1996 + if (message.event.desc != null) { meshes[message.event.meshid].desc = message.event.desc; }
1997 + if (message.event.flags != null) { meshes[message.event.meshid].flags = message.event.flags; }
1998 + if (message.event.consent != null) { meshes[message.event.meshid].consent = message.event.consent; }
1999 + if (message.event.links) { meshes[message.event.meshid].links = message.event.links; }
2000 + if (message.event.amt) { meshes[message.event.meshid].amt = message.event.amt; }
2001 +
2002 + // Check if we lost rights to this mesh in this change.
2003 + if (meshes[message.event.meshid].links[userinfo._id] == null) {
2004 + if ((xxcurrentView == 20) && (currentMesh == meshes[message.event.meshid])) go(2);
2005 + delete meshes[message.event.meshid];
2006 +
2007 + // Delete all nodes in that mesh
2008 + var newnodes = [];
2009 + for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } }
2010 + nodes = newnodes;
2011 +
2012 + // If we are looking at a node in the deleted mesh, move back to "My Devices"
2013 + if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); }
2014 + }
2015 + }
2016 + masterUpdate(4 + 128);
2017 + if (currentNode && (currentNode.meshid == message.event.meshid)) { currentNode = null; if ((xxcurrentView >= 10) && (xxcurrentView < 20)) { go(1); } }
2018 + //meshserver.send({ action: 'files' }); // TODO: Why do we need to do this??
2019 +
2020 + // If we are looking at a mesh that is now deleted, move back to "My Account"
2021 + if (xxcurrentView == 20 && currentMesh._id == message.event.meshid) { masterUpdate(4096); }
2022 + break;
2023 + }
2024 + case 'deletemesh': {
2025 + // Delete the mesh
2026 + if (meshes[message.event.meshid]) {
2027 + delete meshes[message.event.meshid];
2028 + masterUpdate(128);
2029 + meshserver.send({ action: 'files' });
2030 + }
2031 +
2032 + // Delete all nodes in that mesh
2033 + var newnodes = [];
2034 + if (nodes != null) { for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } } }
2035 + nodes = newnodes;
2036 + masterUpdate(4);
2037 +
2038 + // If we are looking at a mesh that is now deleted, move back to "My Account"
2039 + if (xxcurrentView >= 20 && xxcurrentView < 30 && currentMesh._id == message.event.meshid) { setDialogMode(0); go(2); }
2040 + // If we are looking at a node in the deleted mesh, move back to "My Devices"
2041 + if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); }
2042 +
2043 + break;
2044 + }
2045 + case 'addnode': {
2046 + var node = message.event.node;
2047 + 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.
2048 + if (getNodeFromId(node._id) != null) break; // This node is already known.
2049 + node.namel = node.name.toLowerCase();
2050 + if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
2051 + node.meshnamel = meshes[node.meshid].name.toLowerCase();
2052 + node.state = 0;
2053 + if (!node.icon) node.icon = 1;
2054 + node.ident = ++nodeShortIdent;
2055 + if (nodes == null) { }
2056 + nodes.push(node);
2057 +
2058 + // Web page update
2059 + masterUpdate(1 | 2 | 4 | 16);
2060 +
2061 + break;
2062 + }
2063 + case 'removenode': {
2064 + var index = -1;
2065 + for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
2066 + if (index != -1) {
2067 + var node = nodes[index];
2068 + if (currentNode == node) {
2069 + if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); }
2070 + currentNode = null;
2071 + // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
2072 + }
2073 + nodes.splice(index, 1);
2074 +
2075 + // Web page update
2076 + masterUpdate(4 | 16);
2077 + }
2078 + break;
2079 + }
2080 + case 'changenode': {
2081 + var index = -1;
2082 + for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
2083 + if (index != -1) {
2084 + var node = nodes[index];
2085 +
2086 + // Change the node
2087 + node.name = message.event.node.name;
2088 + node.rname = message.event.node.rname;
2089 + node.users = message.event.node.users;
2090 + node.host = message.event.node.host;
2091 + node.desc = message.event.node.desc;
2092 + node.ip = message.event.node.ip;
2093 + node.osdesc = message.event.node.osdesc;
2094 + node.publicip = message.event.node.publicip;
2095 + node.iploc = message.event.node.iploc;
2096 + node.wifiloc = message.event.node.wifiloc;
2097 + node.gpsloc = message.event.node.gpsloc;
2098 + node.tags = message.event.node.tags;
2099 + node.userloc = message.event.node.userloc;
2100 + if (message.event.node.agent != null) {
2101 + if (node.agent == null) node.agent = {};
2102 + if (message.event.node.agent.ver != null) { node.agent.ver = message.event.node.agent.ver; }
2103 + if (message.event.node.agent.id != null) { node.agent.id = message.event.node.agent.id; }
2104 + if (message.event.node.agent.caps != null) { node.agent.caps = message.event.node.agent.caps; }
2105 + if (message.event.node.agent.core != null) { node.agent.core = message.event.node.agent.core; } else { if (node.agent.core) { delete node.agent.core; } }
2106 + node.agent.tag = message.event.node.agent.tag;
2107 + }
2108 + if (message.event.node.intelamt != null) {
2109 + if (node.intelamt == null) node.intelamt = {};
2110 + if (message.event.node.intelamt.state != null) { node.intelamt.state = message.event.node.intelamt.state; }
2111 + if (message.event.node.intelamt.host != null) { node.intelamt.user = message.event.node.intelamt.host; }
2112 + if (message.event.node.intelamt.user != null) { node.intelamt.user = message.event.node.intelamt.user; }
2113 + if (message.event.node.intelamt.tls != null) { node.intelamt.tls = message.event.node.intelamt.tls; }
2114 + if (message.event.node.intelamt.ver != null) { node.intelamt.ver = message.event.node.intelamt.ver; }
2115 + if (message.event.node.intelamt.tag != null) { node.intelamt.tag = message.event.node.intelamt.tag; }
2116 + if (message.event.node.intelamt.uuid != null) { node.intelamt.uuid = message.event.node.intelamt.uuid; }
2117 + if (message.event.node.intelamt.realm != null) { node.intelamt.realm = message.event.node.intelamt.realm; }
2118 + }
2119 + if (message.event.node.av != null) { node.av = message.event.node.av; }
2120 + node.namel = node.name.toLowerCase();
2121 + if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
2122 + if (message.event.node.icon) { node.icon = message.event.node.icon; }
2123 +
2124 + // Web page update
2125 + masterUpdate(2 | 4 | 8 | 16);
2126 + refreshDevice(node._id);
2127 +
2128 + if ((currentNode == node) && (xxdialogMode != null) && (xxdialogTag == '@xxmap')) { p10showNodeLocationDialog(); }
2129 + }
2130 + break;
2131 + }
2132 + case 'nodemeshchange': {
2133 + var index = -1;
2134 + for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
2135 + if (index != -1) {
2136 + var node = nodes[index];
2137 + if (meshes[message.event.newMeshId] == null) {
2138 + // We don't see the new mesh, remove this device
2139 +
2140 + // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
2141 + if (currentNode == node) { if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); } currentNode = null; }
2142 + nodes.splice(index, 1);
2143 + masterUpdate(4 | 16);
2144 + } else {
2145 + // We see the new mesh, move this device
2146 + node.meshid = message.event.newMeshId;
2147 + node.meshnamel = meshes[message.event.newMeshId].name.toLowerCase();
2148 + masterUpdate(1 | 2 | 4);
2149 + }
2150 + refreshDevice(message.event.nodeid);
2151 + } else {
2152 + // This is a new device, add it.
2153 + var node = message.event.node;
2154 + 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.
2155 + node.namel = node.name.toLowerCase();
2156 + if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
2157 + node.meshnamel = meshes[node.meshid].name.toLowerCase();
2158 + node.state = 0;
2159 + if (!node.icon) node.icon = 1;
2160 + node.ident = ++nodeShortIdent;
2161 + if (nodes == null) { }
2162 + nodes.push(node);
2163 +
2164 + // Web page update
2165 + masterUpdate(1 | 2 | 4 | 16);
2166 + }
2167 + break;
2168 + }
2169 + case 'nodeconnect': {
2170 + // Indicated a node has changed connectivity state
2171 + var index = -1;
2172 + for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
2173 + if (index != -1) {
2174 + var node = nodes[index];
2175 +
2176 + // Event the connection change if needed
2177 + var n = getstore('notifications', 0); // Account notification settings
2178 +
2179 + // Per-group notification settings
2180 + if (message.event.meshid && userinfo.links && userinfo.links[message.event.meshid] && userinfo.links[message.event.meshid].notify) {
2181 + n &= userinfo.links[message.event.meshid].notify;
2182 + } else {
2183 + n = 0;
2184 + }
2185 +
2186 + // Show the notification
2187 + if (n & 2) {
2188 + if (((node.conn & 1) == 0) && ((message.event.conn & 1) != 0)) { addNotification({ text: "Agent connected", title: node.name, icon: node.icon, nodeid: node._id }); }
2189 + if (((node.conn & 2) == 0) && ((message.event.conn & 2) != 0)) { addNotification({ text: "Intel AMT detected", title: node.name, icon: node.icon, nodeid: node._id }); }
2190 + 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 }); }
2191 + if (((node.conn & 16) == 0) && ((message.event.conn & 16) != 0)) { addNotification({ text: "MQTT connected", title: node.name, icon: node.icon, nodeid: node._id }); }
2192 + }
2193 + if (n & 4) {
2194 + if (((node.conn & 1) != 0) && ((message.event.conn & 1) == 0)) { addNotification({ text: "Agent disconnected", title: node.name, icon: node.icon, nodeid: node._id }); }
2195 + 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 }); }
2196 + 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 }); }
2197 + if (((node.conn & 16) != 0) && ((message.event.conn & 16) == 0)) { addNotification({ text: "MQTT disconnected", title: node.name, icon: node.icon, nodeid: node._id }); }
2198 + }
2199 +
2200 + // Change the node connection state
2201 + node.conn = message.event.conn;
2202 + node.pwr = message.event.pwr;
2203 +
2204 + // Web page update
2205 + masterUpdate(4 | 16);
2206 + refreshDevice(node._id);
2207 + }
2208 + break;
2209 + }
2210 + case 'wssessioncount': {
2211 + // Update the active web socket session count for a user
2212 + if (wssessions != null) {
2213 + if (message.event.count == 0 && wssessions['user/' + domain + '/' + message.event.username.toLowerCase()]) {
2214 + delete wssessions['user/' + domain + '/' + message.event.username.toLowerCase()];
2215 + } else {
2216 + wssessions['user/' + domain + '/' + message.event.username.toLowerCase()] = message.event.count;
2217 + }
2218 + updateUsers();
2219 + }
2220 + break;
2221 + }
2222 + case 'login': {
2223 + // Update the last login time
2224 + if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) {
2225 + users['user/' + domain + '/' + message.event.username.toLowerCase()].login = Math.floor(new Date(message.event.time).getTime() / 1000);
2226 + }
2227 + break;
2228 + }
2229 + case 'scanamtdevice': {
2230 + // Populate the Intel AMT scan dialog box with the result of the RMCP scan
2231 + if ((xxdialogMode == null) || (!Q('dp1range')) || (Q('dp1range').value != message.event.range)) return;
2232 + var x = '';
2233 + if (message.event.results == null) {
2234 + // The scan could not occur because of an error. Likely the user range was invalid.
2235 + 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>';
2236 + } else {
2237 + // Go thru all the results and populate the dialog box
2238 + amtScanResults = message.event.results;
2239 + for (var i in message.event.results) {
2240 + var r = message.event.results[i], shortname = r.hostname;
2241 + if (shortname.length > 20) { shortname = shortname.substring(0, 20) + '...'; }
2242 + var str = '<b title="' + EscapeHtml(r.hostname) + '">' + EscapeHtml(shortname) + '</b> - v' + r.ver;
2243 + if (r.state == 2) { if (r.tls == 1) { str += "avec TLS."; } else { str += "sans TLS."; } } else { str += ' not activated.'; }
2244 + 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>';
2245 + }
2246 + // If no results where found, display a nice message
2247 + 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>'; }
2248 + }
2249 + // Set the html in the dialog box and re-enable the scan button
2250 + QH('dp1results', x);
2251 + QE('dp1range', true);
2252 + QE('dp1rangebutton', true);
2253 + break;
2254 + }
2255 + case 'notify': {
2256 + var n = { text: message.event.value, title: message.event.title, icon: message.event.icon };
2257 + if (message.event.tag != null) { n.tag = message.event.tag; }
2258 + addNotification(n);
2259 + break;
2260 + }
2261 + case 'traceinfo': {
2262 + if (typeof message.event.traceSources == 'object') {
2263 + if ((message.event.traceSources != null) && (message.event.traceSources.length > 0)) {
2264 + serverTraceSources = message.event.traceSources;
2265 + QH('p41traceStatus', EscapeHtml(message.event.traceSources.join(', ')));
2266 + } else {
2267 + serverTraceSources = [];
2268 + QH('p41traceStatus', "None");
2269 + }
2270 + }
2271 + break;
2272 + }
2273 + case 'sysinfohash': {
2274 + // If the sysinfo document has changed and we are looking at it, request an update.
2275 + if ((currentNode != null) && (message.event.nodeid == powerTimelineReq)) {
2276 + meshserver.send({ action: 'getsysinfo', nodeid: message.event.nodeid });
2277 + }
2278 + break;
2279 + }
2280 + case 'stopped': { // Server is stopping.
2281 + // Disconnect
2282 + //console.log(message.msg);
2283 + break;
2284 + }
2285 + default:
2286 + //console.log('Unknown message.event.action', message.event.action);
2287 + break;
2288 + }
2289 + break;
2290 + }
2291 + case 'createInviteLink': { // Agent installation invitation link
2292 + if (xxdialogTag != message.meshid) break;
2293 + var servername = serverinfo.name;
2294 + 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.
2295 + var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
2296 + var url;
2297 + if (serverinfo.https == true) {
2298 + var portStr = (serverinfo.port == 443) ? '' : (':' + serverinfo.port);
2299 + url = 'https://' + servername + portStr + domainUrl + 'agentinvite?c=' + message.cookie;
2300 + } else {
2301 + var portStr = (serverinfo.port == 80) ? '' : (':' + serverinfo.port);
2302 + url = 'http://' + servername + portStr + domainUrl + 'agentinvite?c=' + message.cookie;
2303 + }
2304 + Q('agentInvitationLink').href = url;
2305 + var t = format("{0} hour{1}", message.expire, addLetterS(message.expire));
2306 + if (message.expire == 24) { t = "1 jour"; }
2307 + if (message.expire == 168) { t = "1 semaine"; }
2308 + if (message.expire == 5040) { t = "1 mois"; }
2309 + if (message.expire == 0) { t = "Illimité"; }
2310 + QH('agentInvitationLink', format("Invitation Link ({0})", t));
2311 + QV('agentInvitationLinkDiv', true);
2312 + break;
2313 + }
2314 + case 'getmqttlogin': {
2315 + if ((currentNode == null) || (currentNode._id != message.nodeid) || (xxdialogMode != null)) return;
2316 + var x = "These settings can be used to connect MQTT for this device." + '<br /><br />';
2317 + delete message.action;
2318 + delete message.nodeid;
2319 + x += '<textarea readonly=readonly style=width:100%;resize:none;height:100px;overflow:auto;font-size:12px readonly>' + JSON.stringify(message) + '</textarea>';
2320 + /*
2321 + x += addHtmlValue('Username', '<input style=width:230px readonly value="' + message.user + '" />');
2322 + x += addHtmlValue('Password', '<input style=width:230px readonly value="' + message.pass + '" />');
2323 + x += addHtmlValue('WS URL', '<input style=width:230px readonly value="' + message.wsUrl + '" />');
2324 + if (message.mpsUrl && message.mpsCertHash) {
2325 + x += addHtmlValue('MPS URL', '<input style=width:230px readonly value="' + message.mpsUrl + '" />');
2326 + x += addHtmlValue('MPS Cert Hash', '<input style=width:230px readonly value="' + message.mpsCertHash + '" />');
2327 + }
2328 + */
2329 + setDialogMode(2, "MQTT Credentials", 1, null, x);
2330 + break;
2331 + }
2332 + case 'stopped': { // Server is stopping.
2333 + // Disconnect
2334 + autoReconnect = false;
2335 + QH('p0span', message.msg);
2336 + break;
2337 + }
2338 + case 'plugin': {
2339 + if ((pluginHandler == null) || (typeof message.plugin != 'string')) break;
2340 + try { pluginHandler[message.plugin][message.method](server, message); } catch (e) { console.log('Error loading plugin handler ('+ e + ')'); }
2341 + break;
2342 + }
2343 + default:
2344 + //console.log('Unknown message.action', message.action);
2345 + break;
2346 + }
2347 + }
2348 +
2349 + //
2350 + // MY DEVICES
2351 + //
2352 +
2353 + function onRealNameCheckBox() {
2354 + showRealNames = Q('RealNameCheckBox').checked;
2355 + putstore('showRealNames', showRealNames ? 1 : 0);
2356 + masterUpdate(6);
2357 + return;
2358 + }
2359 +
2360 + function onDeviceViewChange(i) {
2361 + if (i != null) { Q('viewselect').value = i; }
2362 + for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
2363 + Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
2364 + putstore('_deviceView', Q('viewselect').value);
2365 + putstore('_viewsize', Q('sizeselect').value);
2366 + masterUpdate(4);
2367 + setTimeout(function () { masterUpdate(512); }, 200);
2368 + }
2369 +
2370 + function ondockeypress(e) {
2371 + setSessionActivity();
2372 + if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked) {
2373 + // Check what keys we are allows to send
2374 + if (currentNode != null) {
2375 + var mesh = meshes[currentNode.meshid];
2376 + var meshrights = mesh.links[userinfo._id].rights;
2377 + var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
2378 + if (inputAllowed == false) return false;
2379 + var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
2380 + if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
2381 + }
2382 + return desktop.m.handleKeys(e);
2383 + }
2384 + if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { return terminal.m.TermHandleKeys(e); }
2385 + if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) return agentConsoleHandleKeys(e);
2386 + if (!xxdialogMode && xxcurrentView == 4) {
2387 + if (e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
2388 + var processed = 0;
2389 + if (e.key) {
2390 + if (e.key.length === 1 && userSearchFocus == 0) { Q('UserSearchInput').value = ((Q('UserSearchInput').value + e.key)); processed = 1; }
2391 + if (e.keyCode == 8 && userSearchFocus == 0) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = x.substring(0, x.length - 1); processed = 1; }
2392 + if (e.keyCode == 27) { Q('UserSearchInput').value = ''; processed = 1; }
2393 + } else {
2394 + if (e.charCode != 0 && userSearchFocus == 0) { Q('UserSearchInput').value = ((Q('UserSearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
2395 + }
2396 + if (processed > 0) { if (processed == 1) { onUserSearchInputChanged(); } return haltEvent(e); }
2397 + }
2398 + if (xxdialogMode || xxcurrentView != 1) return;
2399 + if (e.ctrlKey == true && e.charCode == 96) {
2400 + showRealNames = !showRealNames;
2401 + Q('RealNameCheckBox').value = showRealNames;
2402 + putstore('showRealNames', showRealNames ? 1 : 0);
2403 + masterUpdate(6)
2404 + return;
2405 + }
2406 + if (e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
2407 + if (Q('viewselect').value < 3) {
2408 + var processed = 0;
2409 + if (e.key) {
2410 + if (e.key.length === 1 && searchFocus == 0) { Q('SearchInput').value = ((Q('SearchInput').value + e.key)); processed = 1; }
2411 + if (e.keyCode == 8 && searchFocus == 0) { var x = Q('SearchInput').value; Q('SearchInput').value = x.substring(0, x.length - 1); processed = 1; }
2412 + if (e.keyCode == 27) { Q('SearchInput').value = ''; processed = 1; }
2413 + } else {
2414 + if (e.charCode != 0 && searchFocus == 0) { Q('SearchInput').value = ((Q('SearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
2415 + }
2416 + if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
2417 + }
2418 + if (Q('viewselect').value == 3) {
2419 + if (e.key) {
2420 + if (e.key.length === 1 && mapSearchFocus == 0) { Q('mapSearchLocation').value = ((Q('mapSearchLocation').value + e.key)); processed = 1; }
2421 + //if (e.keyCode == 8 && mapSearchFocus == 0) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = x.substring(0, x.length - 1); processed = 1; }
2422 + if (e.keyCode == 27) { Q('mapSearchLocation').value = ''; mapCloseSearchWindow(); processed = 1; }
2423 + if (e.keyCode == 13) { getSearchLocation(); }
2424 + } else {
2425 + if (e.charCode != 0 && mapSearchFocus == 0) { Q('mapSearchLocation').value = ((Q('mapSearchLocation').value + String.fromCharCode(e.charCode))); processed = 1; }
2426 + }
2427 + }
2428 + }
2429 +
2430 + function ondockeydown(e) {
2431 + setSessionActivity();
2432 + if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked) {
2433 + // Check what keys we are allows to send
2434 + if (currentNode != null) {
2435 + var mesh = meshes[currentNode.meshid];
2436 + var meshrights = mesh.links[userinfo._id].rights;
2437 + var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
2438 + if (inputAllowed == false) return false;
2439 + var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
2440 + if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
2441 + }
2442 + return desktop.m.handleKeyDown(e);
2443 + }
2444 + if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { terminal.m.TermHandleKeyDown(e); if ((e.keyCode >= 37) && (e.keyCode <= 40)) { haltEvent(e); } }
2445 + if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { haltEvent(e); return false; } // F5 Refresh on files
2446 + if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) { return agentConsoleHandleKeys(e); }
2447 + if (!xxdialogMode && xxcurrentView == 4) {
2448 + if (e.keyCode === 8 && userSearchFocus == 0) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
2449 + if (e.keyCode === 27) { Q('UserSearchInput').value = ''; processed = 1; }
2450 + if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
2451 + }
2452 + if (xxdialogMode || xxcurrentView != 1 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
2453 + var processed = 0;
2454 + if (Q('viewselect').value < 3) {
2455 + if (e.keyCode === 8 && searchFocus == 0) { var x = Q('SearchInput').value; Q('SearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
2456 + if (e.keyCode === 27) { Q('SearchInput').value = ''; processed = 1; }
2457 + if (processed > 0) { if (processed == 1) { masterUpdate(5); } return haltEvent(e); }
2458 + }
2459 + if (Q('viewselect').value == 3) {
2460 + if (e.keyCode === 8 && mapSearchFocus == 0) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = (x.substring(0, x.length - 1)); processed = 1; }
2461 + if (e.keyCode === 27) { Q('mapSearchLocation').value = ''; mapCloseSearchWindow(); processed = 1; }
2462 + }
2463 + }
2464 +
2465 + function ondockeyup(e) {
2466 + setSessionActivity();
2467 + if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked) {
2468 + // Check what keys we are allows to send
2469 + if (currentNode != null) {
2470 + var mesh = meshes[currentNode.meshid];
2471 + var meshrights = mesh.links[userinfo._id].rights;
2472 + var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
2473 + if (inputAllowed == false) return false;
2474 + var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
2475 + if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
2476 + }
2477 + return desktop.m.handleKeyUp(e);
2478 + }
2479 + if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { return terminal.m.TermHandleKeyUp(e); }
2480 + if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { p13folderup(9999); haltEvent(e); return false; } // F5 Refresh on files
2481 + if (!xxdialogMode && xxcurrentView == 4) { if ((e.keyCode === 8 && searchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
2482 + if (xxdialogMode && e.keyCode == 27) { dialogclose(0); }
2483 + if (xxdialogMode || xxcurrentView != 0 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
2484 + if (Q('viewselect').value < 3) { if ((e.keyCode === 8 && searchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
2485 + if (Q('viewselect').value == 3) { if ((e.keyCode === 8 && mapSearchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
2486 + }
2487 +
2488 + //function ondocfocus() { }
2489 + // TODO: Add handleReleaseKeys() for Intel AMT.
2490 + function ondocblur() { if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked && desktop.m.handleReleaseKeys) { return desktop.m.handleReleaseKeys(); } }
2491 +
2492 + // Highlights the device being hovered
2493 + function devMouseHover(element, over) {
2494 + setSessionActivity();
2495 + var view = Q('viewselect').value;
2496 + if (view == 1) {
2497 + var e = element.children[1].children[1];
2498 + e.children[0].classList.remove('g1s');
2499 + e.children[1].classList.remove('e2s');
2500 + e.children[2].classList.remove('g2s');
2501 + if (over == 1) {
2502 + e.children[0].classList.add('g1s');
2503 + e.children[1].classList.add('e2s');
2504 + e.children[2].classList.add('g2s');
2505 + }
2506 + } else if (view == 2) {
2507 + var e = element;
2508 + e.children[2].classList.remove('g1s');
2509 + e.children[4].classList.remove('e2s');
2510 + e.children[3].classList.remove('g2s');
2511 + if (over == 1) {
2512 + e.children[2].classList.add('g1s');
2513 + e.children[4].classList.add('e2s');
2514 + e.children[3].classList.add('g2s');
2515 + }
2516 + }
2517 + }
2518 +
2519 + var deviceHeaderId = 0;
2520 + var deviceHeaderTotal = 0;
2521 + var deviceHeadersTitles = {};
2522 + var deviceHeaderCount;
2523 + var deviceHeaders = {};
2524 + var oldviewmode = 0;
2525 + function updateDevices() {
2526 + if (nodes == null) { return; }
2527 + var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, view = Q('viewselect').value, groups = {}, groupCount = {};
2528 + QV('xdevices', view < 4);
2529 + QV('xdevicesmap', view == 4);
2530 + QV('devListToolbar', view < 3);
2531 + QV('kvmListToolbar', view == 3);
2532 + QV('devMapToolbar', view == 4);
2533 + QV('devListToolbarSize', view == 3);
2534 + QV('NoMeshesPanel', meshcount == 0);
2535 + //QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0));
2536 + QV('devListToolbarViewIcons', (meshcount != 0) && (nodes.length > 0));
2537 + QV('devListToolbarSort', (meshcount != 0) && (nodes.length > 0) && (view < 4));
2538 + if ((meshcount == 0) || (nodes.length == 0)) { view = 1; sort = 0; }
2539 + if (view == 4) {
2540 + setTimeout( function() { if (xxmap.map != null) { xxmap.map.updateSize(); } }, 200);
2541 + // TODO
2542 + } else {
2543 + // 3 wide, list view or desktop view
2544 + deviceHeaderId = 0;
2545 + deviceHeaderCount = {};
2546 + deviceHeaderTotal = 0;
2547 + deviceHeaders = {};
2548 + deviceHeadersTitles = {};
2549 + var kvmDivs = [];
2550 +
2551 + // Perform node sort
2552 + if (sort == 0) { nodes.sort(meshSort); }
2553 + else if (sort == 1) { nodes.sort(powerSort); }
2554 + else if (sort == 2) { if (showRealNames == true) { nodes.sort(deviceHostSort); } else { nodes.sort(deviceSort); } }
2555 +
2556 + // Save the list of currently checked nodeid's
2557 + var checkedNodeids = [], elements = document.getElementsByClassName('DeviceCheckbox'), checkcount = 0;
2558 + for (var i=0;i<elements.length;i++) { if (elements[i].checked) { checkedNodeids.push(elements[i].value); } }
2559 + if ((oldviewmode < 3) && (view == 3)) { multiDesktopFilter = checkedNodeids; }
2560 + else if ((oldviewmode == 3) && (view < 3)) { checkedNodeids = multiDesktopFilter; }
2561 +
2562 + // Compute the width of the device view.
2563 + var totalDeviceViewWidth = Q('column_l').clientWidth - 60;
2564 + var deviceBoxWidth = Math.floor(totalDeviceViewWidth / 301);
2565 + deviceBoxWidth = 301 + Math.floor((totalDeviceViewWidth - (deviceBoxWidth * 301)) / deviceBoxWidth);
2566 +
2567 + if ((view == 2) && (sort != 3)) {
2568 + 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';
2569 + }
2570 +
2571 + // Go thru the list of nodes and display them
2572 + for (var i in nodes) {
2573 + var node = nodes[i];
2574 + if (node.v == false) continue;
2575 + var mesh2 = meshes[node.meshid], meshlinks = mesh2.links[userinfo._id];
2576 + if (meshlinks == null) continue;
2577 + var meshrights = meshlinks.rights;
2578 + if ((view == 3) && (mesh2.mtype == 1)) continue;
2579 + if (sort == 0) {
2580 + // Mesh header
2581 + if (node.meshid != current) {
2582 + deviceHeaderSet();
2583 + var extra = '';
2584 + if (view == 2) { r += '<tr><td colspan=5>'; }
2585 + if (meshes[node.meshid].mtype == 1) { extra = '<span class=devHeaderx>' + ", Intel&reg; AMT only" + '</span>'; }
2586 + if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
2587 + if (view == 2) { r += '<div>'; }
2588 + r += '<div class=DevSt style=width:100%;padding-top:4px><span style=float:right>';
2589 + r += '<span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx></span>' + extra;
2590 + 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>';
2591 + if (view == 2) { r += '</div>'; }
2592 + current = node.meshid;
2593 + displayedMeshes[current] = 1;
2594 + c = 0;
2595 + }
2596 + } else if (sort == 1) {
2597 + // Power header
2598 + var pwr = node.pwr?node.pwr:0;
2599 + if (pwr !== current) {
2600 + deviceHeaderSet();
2601 + if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
2602 +
2603 + if (view == 2) { r += '<tr><td>'; }
2604 + 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>';
2605 +
2606 + current = pwr;
2607 + c = 0;
2608 + }
2609 + } else if (sort == 2) {
2610 + // Device header
2611 + if (current == null) { current = '1'; }
2612 + }
2613 +
2614 + count++;
2615 + var title = EscapeHtml(node.name);
2616 + if (title.length == 0) { title = '<i>' + "None" + '</i>'; }
2617 + if ((node.rname != null) && (node.rname.length > 0)) { title += ' / ' + EscapeHtml(node.rname); }
2618 + var name = EscapeHtml(node.name);
2619 + if (showRealNames == true && node.rname != null) name = EscapeHtml(node.rname);
2620 + if (name.length == 0) { name = '<i>' + "None" + '</i>'; }
2621 +
2622 + // Node
2623 + var icon = node.icon;
2624 + if ((!node.conn) || (node.conn == 0)) { icon += ' gray'; }
2625 + if (view == 1) {
2626 + 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>';
2627 + } else if (view == 2) {
2628 + var states = [];
2629 + if (node.conn) {
2630 + if ((node.conn & 1) != 0) { states.push('<span title=\"' + "Mesh agent is connected and ready for use." + '\">' + "Agent" + '</span>'); }
2631 + if ((node.conn & 2) != 0) { states.push('<span title=\"' + "Intel&reg; AMT CIRA is connected and ready for use." + '\">' + "CIRA" + '</span>'); }
2632 + else if ((node.conn & 4) != 0) { states.push('<span title=\"' + "Intel&reg; AMT is routable." + '\">' + "AMT" + '</span>'); }
2633 + if ((node.conn & 8) != 0) { states.push('<span title=\"' + "Mesh agent is reachable using another agent as relay." + '\">' + "Relay" + '</span>'); }
2634 + if ((node.conn & 16) != 0) { states.push('<span title=\"' + "MQTT connection to the device is active." + '\">' + "MQTT" + '</span>'); }
2635 + }
2636 + 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)">';
2637 + r += '<div class=deviceBarCheckbox><input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox></div>';
2638 + 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>';
2639 + r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
2640 + 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>';
2641 + r += '<td style=text-align:center>' + getUserShortStr(node);
2642 + r += '<td style=text-align:center>' + (node.ip != null ? node.ip : '');
2643 + r += '<td style=text-align:center>' + states.join('&nbsp;+&nbsp;');
2644 + //r += '<td style=text-align:center>' + (node.pwr != null ? powerStateStrings[node.pwr] : '');
2645 + r += '</tr>';
2646 + } 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.
2647 + if ((multiDesktopFilter) && ((multiDesktopFilter.length == 0) || (multiDesktopFilter.indexOf('devid_' + node._id) >= 0))) {
2648 + 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)">';
2649 + //r += '<input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox style=float:left>';
2650 + r += '<div class="j' + icon + '" style=width:16px;float:left></div>&nbsp;' + name + '</div>';
2651 + 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>';
2652 + r += '</div>';
2653 + kvmDivs.push(node._id);
2654 + }
2655 + }
2656 +
2657 + // If we are displaying devices by group, put the device in the right group.
2658 + if ((sort == 3) && (r != '')) {
2659 + if (node.tags) {
2660 + for (var j in node.tags) {
2661 + var tag = node.tags[j];
2662 + if (groups[tag] == null) { groups[tag] = r; groupCount[tag] = 1; } else { groups[tag] += r; groupCount[tag] += 1; }
2663 + if (view == 3) break;
2664 + }
2665 + }
2666 + r = '';
2667 + }
2668 +
2669 + deviceHeaderTotal++;
2670 + if (typeof deviceHeaderCount[node.state] == 'undefined') { deviceHeaderCount[node.state] = 1; } else { deviceHeaderCount[node.state]++; }
2671 + }
2672 +
2673 + // Display "connect all" and "auto"
2674 + QV('kvmMultiConnectButtonSpan', (kvmDivs.length < 128));
2675 + QV('kvmAutoConnectButtonSpan', (kvmDivs.length < 128));
2676 + if (kvmDivs.length >= 64) { Q('autoConnectDesktopCheckbox').checked = false; }
2677 +
2678 + // If displaying devices by groups, sort the group names and display the devices.
2679 + if (sort == 3) {
2680 + if (view == 2) { 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"; }
2681 +
2682 + var groupNames = [];
2683 + for (var i in groups) { groupNames.push(i); }
2684 + groupNames.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); });
2685 + for (var j in groupNames) {
2686 + var i = groupNames[j];
2687 + if (view == 2) {
2688 + r += '<tr><td colspan=4><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];
2689 + } else {
2690 + 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];
2691 + }
2692 + }
2693 + }
2694 +
2695 + // If there is nothing to display, explain the problem
2696 + if ((r == '') && (meshcount > 0) && (Q('SearchInput').value != '')) {
2697 + if (sort == 3) {
2698 + r = '<div style="margin:30px">' + "No devices are included in any groups, click on a device\'s \"Groups\" to add to a group." + '</div>';
2699 + } else {
2700 + r = '<div style="margin:30px">' + "No devices matching this search." + '</div>';
2701 + }
2702 + }
2703 +
2704 + if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding
2705 +
2706 + // Display all empty device groups, we need to do this because users can add devices to these at any time.
2707 + if ((sort == 0) && (Q('SearchInput').value == '') && (view < 3)) {
2708 + for (var i in meshes) {
2709 + var mesh = meshes[i], meshlink = mesh.links[userinfo._id];
2710 + if (meshlink != null) {
2711 + var meshrights = meshlink.rights;
2712 + if (displayedMeshes[mesh._id] == null) {
2713 + if ((current != '') && (r != '')) { r += '</tr></table>'; }
2714 + 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>';
2715 + r += getMeshActions(mesh, meshrights);
2716 + r += '</span></td></tr><tr>';
2717 + if (mesh.mtype == 1) {
2718 + r += '<td><div style=padding:10px><i>' + "No Intel&reg; AMT devices in this mesh";
2719 + if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addDeviceToMesh(\"' + mesh._id + '\")\'>' + "add one" + '</a>'; }
2720 + }
2721 + if (mesh.mtype == 2) {
2722 + r += '<td><div style=padding:10px><i>' + "No devices in this mesh";
2723 + if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addAgentToMesh(\"' + mesh._id + '\")\'>' + "add one" + '</a>'; }
2724 + }
2725 + r += '.</i></div></td>';
2726 + current = mesh._id;
2727 + count++;
2728 + }
2729 + }
2730 + }
2731 + }
2732 + r += '</tr></table><div style=height:1px></div>'; // This height of 1 div fixes a problem in Linux firefox browsers
2733 +
2734 + // Add a "Add Device Group" option
2735 + r += '<div style=border-top-style:solid;border-top-width:1px;border-top-color:#DDDDDD;cursor:pointer;font-size:10px>';
2736 + if ((view < 3) && (sort == 0) && (meshcount > 0) && ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 64) == 0))) {
2737 + r += '<a href=# onclick="return account_createMesh()" title=\"' + "Create a new group of devices." + '\" style=cursor:pointer>' + "Add Device Group" + '</a>&nbsp';
2738 + }
2739 + if ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 128) == 0)) {
2740 + r += '<a href=# onclick=\'return p10showMeshCmdDialog(0)\' style=cursor:pointer title=\"' + "Download MeshCmd, a command line tool that performs many functions." + '\">' + "MeshCmd" + '</a>&nbsp';
2741 + 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>&nbsp'; }
2742 + }
2743 + r += '</div><br/>';
2744 +
2745 + QH('xdevices', r);
2746 + deviceHeaderSet();
2747 +
2748 + // Re-check nodeid's
2749 + var elements = document.getElementsByClassName('DeviceCheckbox'), checkcount = 0;
2750 + if (checkedNodeids) { for (var i=0;i<elements.length;i++) { elements[i].checked = (checkedNodeids.indexOf(elements[i].value) >= 0); } }
2751 +
2752 + for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
2753 + for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
2754 + p1updateInfo();
2755 +
2756 + // Take care of KVM surfaces in desktop view mode
2757 + if (view == 3) {
2758 + // Figure out and adjust the size to fill the width of the div
2759 + var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
2760 + //var realw = vsize.x + 2, tw = Q('xdevices').clientWidth - 30, xw = Math.floor(tw / realw);
2761 + var realw = vsize.x + 2, tw = totalDeviceViewWidth - 5, xw = Math.floor(tw / realw);
2762 + xw = realw + Math.floor((tw - (xw * realw)) / xw);
2763 + vsize.y = vsize.y * (xw / vsize.x);
2764 + vsize.x = xw;
2765 +
2766 + for (var i in multiDesktop) { multiDesktop[i].xxdelete = true; }
2767 + for (var i in kvmDivs) {
2768 + var id = kvmDivs[i], shortid = id.split('/')[2], desk = multiDesktop[id];
2769 + if (desk != null) {
2770 + // This device already has a canvas, use it.
2771 + desk.m.CanvasId.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
2772 + Q('xkvmid_' + shortid).appendChild(desk.m.CanvasId);
2773 + delete desk.xxdelete;
2774 + QH('skvmid_' + shortid, ["Disconnected", "Connecting...", "Setup...", '', ''][((desk.m.State == null)?desk.m.state:desk.m.State)]);
2775 + } else {
2776 + var node = getNodeFromId(id);
2777 + if ((desktopNode == node) && (desktop != null)) { // Check if the main desktop is this device, if it is, use that.
2778 + // This device already has a canvas, use it.
2779 + var c = desktop.m.CanvasId;
2780 + c.setAttribute('id', 'kvmid_' + shortid);
2781 + c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
2782 + c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
2783 + c.removeAttribute('onmousedown');
2784 + c.removeAttribute('onmouseup');
2785 + c.removeAttribute('onmousemove');
2786 + Q('xkvmid_' + shortid).appendChild(c);
2787 + QH('skvmid_' + shortid, ["Disconnected", "Connecting...", "Setup...", '', ''][((desktop.m.State == null)?desktop.m.state:desktop.m.State)]);
2788 + if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
2789 + desktop.shortid = shortid;
2790 + desktop.onStateChanged = onMultiDesktopStateChange;
2791 + multiDesktop[id] = desktop;
2792 + desktop = desktopNode = currentNode = null;
2793 + // Setup a replacement desktop
2794 + QH('DeskParent', '<canvas id="Desk" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
2795 + } else {
2796 + // This is a new device, create a canvas for it.
2797 + var c = document.createElement('canvas');
2798 + c.setAttribute('id', 'kvmid_' + shortid);
2799 + c.setAttribute('width', 640);
2800 + c.setAttribute('height', 480);
2801 + c.setAttribute('oncontextmenu', 'return false');
2802 + c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
2803 + c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
2804 + try { Q('xkvmid_' + shortid).appendChild(c); } catch (ex) {}
2805 + // Check if we need to auto-connect
2806 + if (Q('autoConnectDesktopCheckbox').checked == true) { setTimeout(function() { connectMultiDesktop(node, 1); }, 100); }
2807 + }
2808 + }
2809 + }
2810 + for (var i in multiDesktop) {
2811 + // If a device is no longer viewed, disconnect it.
2812 + if (multiDesktop[i].xxdelete == true) { multiDesktop[i].Stop(); delete multiDesktop[i]; }
2813 + else if (debugmode && multiDesktop[i].m && multiDesktop[i].m.onScreenSizeChange) {
2814 + mdeskAdjust(multiDesktop[i].m, multiDesktop[i].m.ScreenWidth, multiDesktop[i].m.ScreenHeight, multiDesktop[i].m.CanvasId); // Adjust screen size change
2815 + }
2816 + }
2817 + deskAdjust();
2818 + } else {
2819 + disconnectAllKvmFunction();
2820 + Q('autoConnectDesktopCheckbox').checked = false;
2821 + }
2822 + }
2823 + oldviewmode = view;
2824 + }
2825 +
2826 + function toggleKvmDevice(nodeid) {
2827 + var node = getNodeFromId(nodeid), mesh = meshes[node.meshid], meshrights = mesh.links[userinfo._id].rights;
2828 + if ((meshrights & 8) || (meshrights & 256)) { // Requires remote control rights or desktop view only rights
2829 + //var conn = 0;
2830 + //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)
2831 + if (node.conn & 1) { connectMultiDesktop(node, 1); }
2832 + }
2833 + }
2834 +
2835 + function getUserShortStr(node) {
2836 + if (node == null || node.users == null || node.users.length == 0) return '';
2837 + if (node.users.length > 1) { return '<span title="' + EscapeHtml(node.users.join(', ')) + '">' + nobreak(format("{0} users", node.users.length)) + '</span>'; }
2838 + var u = node.users[0], su = u, i = u.indexOf('\\');
2839 + if (i > 0) { su = u.substring(i + 1); }
2840 + su = EscapeHtml(su);
2841 + if (su.length > 15) { su = su.substring(0, 14) + '&#8230;'; }
2842 + return '<span title="' + EscapeHtml(u) + '">' + su + '</span>';
2843 + }
2844 +
2845 + function autoConnectDesktops() { if (Q('autoConnectDesktopCheckbox').checked == true) { connectAllKvmFunction(); } }
2846 + function connectAllKvmFunction() { for (var i in nodes) { if (multiDesktop[nodes[i]._id] == null) { toggleKvmDevice(nodes[i]._id); } } }
2847 + function disconnectAllKvmFunction() { for (var nodeid in multiDesktop) { multiDesktop[nodeid].Stop(); } multiDesktop = {}; }
2848 + function onMultiDesktopStateChange(desk, state) { try { QH('skvmid_' + desk.shortid, ["Disconnected", "Connecting...", "Setup...", '', ''][state]); } catch (ex) {} }
2849 +
2850 + function showMultiDesktopSettings() {
2851 + QV('d7amtkvm', false);
2852 + QV('d7meshkvm', true);
2853 + d7bitmapquality.value = multidesktopsettings.quality;
2854 + d7bitmapscaling.value = multidesktopsettings.scaling;
2855 + if (multidesktopsettings.framerate) { d7framelimiter.value = multidesktopsettings.framerate; } else { d7framelimiter.value = 1000; }
2856 + setDialogMode(7, "Remote Desktop Settings", 3, showMultiDesktopSettingsChanged);
2857 + }
2858 +
2859 + function showMultiDesktopSettingsChanged() {
2860 + multidesktopsettings.quality = d7bitmapquality.value;
2861 + multidesktopsettings.scaling = d7bitmapscaling.value;
2862 + multidesktopsettings.framerate = d7framelimiter.value;
2863 + localStorage.setItem('multidesktopsettings', JSON.stringify(multidesktopsettings));
2864 + // Make changes to all current connections
2865 + for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
2866 + }
2867 +
2868 + function connectMultiDesktop(node, contype) {
2869 + var nodeid = node._id, shortid = nodeid.split('/')[2];
2870 + var desk = multiDesktop[nodeid];
2871 + if (desk == null) {
2872 + if (Q('kvmid_' + shortid) == null) return; // Check if this device is being displayed, if not, exit now.
2873 + if (contype == 2) {
2874 + // Setup the Intel AMT remote desktop
2875 + if ((node.intelamt.user == null) || (node.intelamt.user == '')) { return; }
2876 + desk = CreateAmtRedirect(CreateAmtRemoteDesktop('kvmid_' + shortid), authCookie);
2877 + desk.shortid = shortid;
2878 + //desk.debugmode = debugmode;
2879 + desk.onStateChanged = onMultiDesktopStateChange;
2880 + desk.m.bpp = 1;
2881 + desk.m.useZRLE = true;
2882 + desk.m.showmouse = true;
2883 + 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.
2884 + //desk.m.onScreenSizeChange = deskAdjust;
2885 + if (debugmode > 0) { desk.m.onScreenSizeChange = mdeskAdjust; } // Multi-Desktop Adjust
2886 + desk.Start(nodeid, 16994, '*', '*', 0);
2887 + desk.contype = 2;
2888 + multiDesktop[nodeid] = desk;
2889 + } else if (contype == 1) {
2890 + // Setup the Mesh Agent remote desktop
2891 + desk = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('kvmid_' + shortid), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
2892 + desk.shortid = shortid;
2893 + desk.attemptWebRTC = attemptWebRTC;
2894 + desk.onStateChanged = onMultiDesktopStateChange;
2895 + //desk.onConsoleMessageChange = function () { console.log('CONSOLEMSG:', desk.consoleMessage); }
2896 + desk.m.CompressionLevel = multidesktopsettings.quality;
2897 + desk.m.ScalingLevel = multidesktopsettings.scaling;
2898 + desk.m.FrameRateTimer = multidesktopsettings.framerate;
2899 + //desk.m.onDisplayinfo = deskDisplayInfo;
2900 + //desk.m.onScreenSizeChange = deskAdjust;
2901 + if (debugmode > 0) { desk.m.onScreenSizeChange = mdeskAdjust; } // Multi-Desktop Adjust
2902 + desk.Start(nodeid);
2903 + desk.contype = 1;
2904 + multiDesktop[nodeid] = desk;
2905 + }
2906 + } else {
2907 + // Disconnect and clean up the remote desktop
2908 + desk.Stop();
2909 + delete multiDesktop[nodeid];
2910 + }
2911 + }
2912 +
2913 + function getMeshActions(mesh, meshrights) {
2914 + if ((meshrights & 4) == 0) return '';
2915 + var r = '';
2916 + if ((features & 1024) == 0) { // If CIRA is allowed
2917 + r += ' <a href=# style=cursor:pointer;font-size:10px title=\"' + "Add a new Intel&reg; AMT computer that is located on the internet." + '\" onclick=\'return addCiraDeviceToMesh(\"' + mesh._id + '\")\'>' + "Add CIRA" + '</a>';
2918 + }
2919 + if (mesh.mtype == 1) {
2920 + if ((features & 1) == 0) { // If not WAN-Only
2921 + r += ' <a href=# style=cursor:pointer;font-size:10px title=\"' + "Add a new Intel&reg; AMT computer that is located on the local network." + '\" onclick=\'return addDeviceToMesh(\"' + mesh._id + '\")\'>' + "Add Local" + '</a>';
2922 + r += ' <a href=# style=cursor:pointer;font-size:10px title=\"' + "Add a new Intel&reg; AMT computer by scanning the local network." + '\" onclick=\'return addAmtScanToMesh(\"' + mesh._id + '\")\'>' + "Scan Network" + '</a>';
2923 + }
2924 + if (mesh.amt && (mesh.amt.type == 2)) { // CCM activation
2925 + 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>';
2926 + } else if (mesh.amt && (mesh.amt.type == 3) && ((features & 0x00100000) != 0)) { // ACM activation
2927 + 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>';
2928 + }
2929 + }
2930 + if (mesh.mtype == 2) {
2931 + 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 + '\")\'>' + "Ajouter un agent" + '</a>';
2932 + if ((features & 2) == 0) { 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>'; }
2933 + }
2934 + return r;
2935 + }
2936 +
2937 + function addDeviceToMesh(meshid) {
2938 + if (xxdialogMode) return false;
2939 + var mesh = meshes[meshid];
2940 + var x = format("Add a new Intel&reg; AMT device to device group \"{0}\".", EscapeHtml(mesh.name)) + '<br /><br />';
2941 + x += addHtmlValue("Device Name", '<input id=dp1devicename style=width:230px maxlength=32 autocomplete=off onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
2942 + x += addHtmlValue("Hostname", '<input id=dp1hostname style=width:230px maxlength=32 autocomplete=off placeholder=\"' + "Same as device name" + '\" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
2943 + x += addHtmlValue("Nom d'utilisateur", '<input id=dp1username style=width:230px maxlength=32 autocomplete=off placeholder=\"' + "admin" + '\" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
2944 + x += addHtmlValue("Password", '<input id=dp1password type=password style=width:230px autocomplete=off maxlength=32 onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
2945 + x += addHtmlValue("Security", '<select id=dp1tls style=width:236px><option value=0>' + "No TLS security" + '</option><option value=1>' + "Sécurité TLS requise" + '</option></select>');
2946 + setDialogMode(2, "Add Intel&reg; AMT device", 3, addDeviceToMeshEx, x, meshid);
2947 + validateDeviceToMesh();
2948 + Q('dp1devicename').focus();
2949 + return false;
2950 + }
2951 +
2952 + // Intel AMT CCM Activation
2953 + function showCcmActivation(meshid) {
2954 + if (xxdialogMode) return false;
2955 + var servername = serverinfo.name, mesh = meshes[meshid];
2956 + 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.
2957 + var url, domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
2958 + if (serverinfo.https == true) {
2959 + var portStr = (serverinfo.port == 443) ? '' : (':' + serverinfo.port);
2960 + url = 'wss://' + servername + portStr + domainUrl;
2961 + } else {
2962 + var portStr = (serverinfo.port == 80) ? '' : (':' + serverinfo.port);
2963 + url = 'ws://' + servername + portStr + domainUrl;
2964 + }
2965 + var x = format("Perform Intel AMT client control mode (CCM) activation to group \"{0}\" by downloading the MeshCMD tool and running it like this:", EscapeHtml(mesh.name)) + '<br /><br />';
2966 + 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>';
2967 + setDialogMode(2, "Intel&reg; AMT activation", 9, null, x);
2968 + Q('idx_dlgOkButton').focus();
2969 + return false;
2970 + }
2971 +
2972 + // Intel AMT ACM Activation
2973 + function showAcmActivation(meshid) {
2974 + if (xxdialogMode) return false;
2975 + var servername = serverinfo.name, mesh = meshes[meshid];
2976 + 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.
2977 + var url, domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
2978 + if (serverinfo.https == true) {
2979 + var portStr = (serverinfo.port == 443) ? '' : (':' + serverinfo.port);
2980 + url = 'wss://' + servername + portStr + domainUrl;
2981 + } else {
2982 + var portStr = (serverinfo.port == 80) ? '' : (':' + serverinfo.port);
2983 + url = 'ws://' + servername + portStr + domainUrl;
2984 + }
2985 + var x = format("Perform Intel AMT admin control mode (ACM) activation to group \"{0}\" by downloading the MeshCMD tool and running it like this:", EscapeHtml(mesh.name)) + '<br /><br />';
2986 + 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>';
2987 + if (serverinfo.amtAcmFqdn != null) {
2988 + 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>');
2989 + }
2990 + setDialogMode(2, "Intel&reg; AMT activation", 9, null, x);
2991 + Q('idx_dlgOkButton').focus();
2992 + return false;
2993 + }
2994 +
2995 + // Display the Intel AMT scanning dialog box
2996 + function addAmtScanToMesh(meshid) {
2997 + if (xxdialogMode) return false;
2998 + var x = "Enter a range of IP addresses to scan for Intel AMT devices." + '<br /><br />';
2999 + 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>');
3000 + x += '<div id=dp1results style="width:100%;height:200px;background-color:white;border:1px gray solid;overflow-y:scroll"></div>';
3001 + setDialogMode(2, "Scan for Intel&reg; AMT devices", 3, addAmtScanToMeshEx, x, meshid);
3002 + QE('idx_dlgOkButton', false);
3003 + 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>');
3004 + focusTextBox('dp1range');
3005 + return false;
3006 + }
3007 +
3008 + function addAmtScanToMeshKeyUp(e) {
3009 + if (e.keyCode == 13) { haltEvent(e); addAmtScanToMeshButton(); }
3010 + }
3011 +
3012 + // Called when OK is pressed on the Intel AMT scanning box
3013 + function addAmtScanToMeshEx(button, meshid) {
3014 + var elements = document.getElementsByClassName('DevScanCheckbox'), checkcount = 0;
3015 + for (var i=0;i<elements.length;i++) {
3016 + if (elements[i].checked) {
3017 + var ipaddr = elements[i].getAttribute('tag');
3018 + var amtinfo = amtScanResults[ipaddr];
3019 + meshserver.send({ action: 'addamtdevice', meshid: meshid, devicename: ipaddr, hostname: amtinfo.hostname, amtusername: '', amtpassword: '', amttls: amtinfo.tls });
3020 + }
3021 + }
3022 + }
3023 +
3024 + // If the user presses the "Scan" button on the Intel AMT scanning dialog box, start a scan.
3025 + function addAmtScanToMeshButton() {
3026 + QE('dp1range', false);
3027 + QE('dp1rangebutton', false);
3028 + QH('dp1results', '<div style=width:100%;text-align:center;margin-top:12px>' + "Scanning..." + '</div>');
3029 + meshserver.send({ action: 'scanamtdevice', range: Q('dp1range').value });
3030 + }
3031 +
3032 + // Called when a scanned computer is checked or unchecked.
3033 + function addAmtScanToMeshCheckbox() {
3034 + var elements = document.getElementsByClassName('DevScanCheckbox'), checkcount = 0;
3035 + for (var i=0;i<elements.length;i++) { if (elements[i].checked) checkcount++; }
3036 + QE('idx_dlgOkButton', checkcount > 0);
3037 + }
3038 +
3039 + function addCiraDeviceToMesh(meshid) {
3040 + if (xxdialogMode) return false;
3041 + var mesh = meshes[meshid];
3042 +
3043 + // Replace non alphabetic characters (@ and $) with 'X' because MPS username cannot accept it.
3044 + var meshidx = meshid.split('/')[2].replace(/\@/g, 'X').replace(/\$/g, 'X');
3045 +
3046 + var y = '<select id=dlgAddCiraSel onclick=dlgAddCiraSelClick() style=width:230px><option value=0>' + "MeshCommander Script" + '</option><option value=1>' + "Manual Username/Password" + '</option>';
3047 + 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.
3048 +
3049 + var x = '';
3050 + x += addHtmlValue("Setup Method", y);
3051 + x += '<hr>';
3052 +
3053 + // Setup CIRA using a MeshCommander script (Pretty Simple)
3054 + x += '<div id=dlgAddCira0>' + format("To add a new Intel&reg; AMT device to device group \"{0}\" 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.", EscapeHtml(mesh.name)) + '<br /><br />';
3055 + //x += addHtmlValue('Setup CIRA', '<a href="mescript.ashx?type=1&meshid=' + meshidx.substring(0, 16) + '" download>cira_setup.mescript</a>');
3056 + x += addHtmlValue("Setup CIRA", '<a href="mescript.ashx?type=1&meshid=' + meshid + '" download>cira_setup.mescript</a>');
3057 + x += addHtmlValue("Cleanup CIRA", '<a href="mescript.ashx?type=2" download>cira_clean.mescript</a>');
3058 + x += '</div>';
3059 +
3060 + // Setup CIRA with user/pass authentication (Somewhat difficult)
3061 + x += '<div id=dlgAddCira1 style=display:none>' + format("To add a new Intel&reg; AMT device to device group \"{0}\" with CIRA, load the following certificate as trusted root within Intel AMT", EscapeHtml(mesh.name));
3062 + if (serverinfo.mpspass) { x += ("et authentifiez-vous sur le serveur en utilisant ce nom d'utilisateur et mot de passe." + '<br /><br />'); } else { x += ("et vous authentifier sur le serveur en utilisant ce nom d'utilisateur et n'importe quel mot de passe." + '<br /><br />'); }
3063 + x += addHtmlValue("Root Certificate", '<a href=\"' + "MeshServerRootCert.cer" + '\" download>' + "Root Certificate File" + '</a>');
3064 + x += addHtmlValue("Nom d'utilisateur", '<input style=width:230px readonly value="' + meshidx.substring(0, 16) + '" />');
3065 + if (serverinfo.mpspass) { x += addHtmlValue("Password", '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpspass) + '" />'); }
3066 + if (serverinfo != null) { x += addHtmlValue("MPS Server", '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
3067 + x += '</div>';
3068 +
3069 + // Setup CIRA with certificate authentication (Really difficult, only if TLS offload is not used)
3070 + if ((features & 16) == 0) {
3071 + x += '<div id=dlgAddCira2 style=display:none>' + format("To add a new Intel&reg; AMT device to device group \"{0}\" 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.", EscapeHtml(mesh.name)) + '<br /><br />';
3072 + x += addHtmlValue("Root Certificate", '<a href="MeshServerRootCert.cer" download>' + "Root Certificate File" + '</a>');
3073 + x += addHtmlValue("Organization", '<input style=width:230px readonly value="' + meshidx + '" />');
3074 + if (serverinfo != null) { x += addHtmlValue("MPS Server", '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
3075 + x += '</div>';
3076 + }
3077 +
3078 + setDialogMode(2, "Add Intel&reg; AMT CIRA device", 2, null, x, 'fileDownload');
3079 + Q('dlgAddCiraSel').focus();
3080 + return false;
3081 + }
3082 +
3083 + function dlgAddCiraSelClick() {
3084 + var val = Q('dlgAddCiraSel').value;
3085 + QV('dlgAddCira0', val == 0);
3086 + QV('dlgAddCira1', val == 1);
3087 + QV('dlgAddCira2', val == 2);
3088 + }
3089 +
3090 + // Return true is the input string looks like an email address
3091 + function checkEmail(str) {
3092 + var x = str.split('@');
3093 + var ok = ((x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2));
3094 + if (ok == true) { var y = x[1].split('.'); for (var i in y) { if (y[i].length == 0) { ok = false; } } }
3095 + return ok;
3096 + }
3097 +
3098 + function inviteAgentToMesh(meshid) {
3099 + if (xxdialogMode) return false;
3100 + var x = '', mesh = meshes[meshid];
3101 + if (features & 64) {
3102 + 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 />';
3103 + x += '<div id=emailInviteDiv style=display:none>' + format("Invite someone to install the mesh agent. An email with be sent with the link to the mesh agent installation for the \"{0}\" device group.", EscapeHtml(mesh.name)) + '<br /><br />';
3104 + x += addHtmlValue("Name (optional)", '<input id=agentInviteName value="" style=width:230px maxlength=64 />');
3105 + x += addHtmlValue("Email", '<input id=agentInviteEmail style=width:230px placeholder=\"' + "example@email.com" + '\" onkeyup=validateAgentInvite()></input>');
3106 + 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>');
3107 + x += '<div id=d2agentexpirediv>';
3108 + x += addHtmlValue("Link Expiration", '<select id=agentInviteExpire style=width:236px><option value=1>' + "1 heure" + '</option><option value=8>' + "8 heures" + '</option><option value=24>' + "1 jour" + '</option><option value=168>' + "1 semaine" + '</option><option value=5040>' + "1 mois" + '</option><option value=0>' + "Illimité" + '</option></select>');
3109 + x += '</div>';
3110 + 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>');
3111 + x += addHtmlValue("Message" + '<br />' + "(optional)", '<textarea id=agentInviteMessage value="" style=width:230px;height:100px;resize:none maxlength=1024 /></textarea>');
3112 + x += '</div>';
3113 + }
3114 + x += '<div id=urlInviteDiv>' + format("Invite someone to install the mesh agent by sharing an invitation link. This link points the user to installation instructions for the \"{0}\" device group. The link is public and no account for this server is needed.", EscapeHtml(mesh.name)) + '<br /><br />';
3115 + x += addHtmlValue("Link Expiration", '<select id=d2inviteExpire style=width:236px onchange=d2RequestInvitationLink()><option value=1>' + "1 heure" + '</option><option value=8>' + "8 heures" + '</option><option value=24>' + "1 jour" + '</option><option value=168>' + "1 semaine" + '</option><option value=5040>' + "1 mois" + '</option><option value=0>' + "Illimité" + '</option></select>');
3116 + 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>';
3117 + setDialogMode(2, "Invite", 3, performAgentInvite, x, meshid);
3118 + if (features & 64) { Q('d2InviteType').focus(); d2ChangedInviteType(); } else { Q('d2inviteExpire').focus(); validateAgentInvite(); }
3119 + d2RequestInvitationLink();
3120 + return false;
3121 + }
3122 +
3123 + function d2RequestInvitationLink() {
3124 + meshserver.send({ action: 'createInviteLink', meshid: xxdialogTag, expire: parseInt(Q('d2inviteExpire').value), flags: 0 });
3125 + }
3126 +
3127 + function d2ChangedInviteType() {
3128 + QV('urlInviteDiv', Q('d2InviteType').value == 0);
3129 + QV('d2agentexpirediv', Q('agentInviteNameOs').value == 4);
3130 + QV('emailInviteDiv', Q('d2InviteType').value == 1);
3131 + validateAgentInvite();
3132 + }
3133 +
3134 + function d2CopyInviteToClip() { copyTextToClip(Q('agentInvitationLink').href); }
3135 +
3136 + function validateAgentInvite() {
3137 + if ((features & 64) && (Q('d2InviteType').value == 1)) {
3138 + QE('idx_dlgOkButton', checkEmail(Q('agentInviteEmail').value));
3139 + QV('idx_dlgCancelButton', true);
3140 + } else {
3141 + QE('idx_dlgOkButton', true);
3142 + QV('idx_dlgCancelButton', false);
3143 + }
3144 + }
3145 +
3146 + function performAgentInvite(button, meshid) {
3147 + if ((features & 64) && (Q('d2InviteType').value == 1)) {
3148 + 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) });
3149 + }
3150 + }
3151 +
3152 + function addAgentToMesh(meshid) {
3153 + if (xxdialogMode) return false;
3154 + var mesh = meshes[meshid], x = '', installType = 0;
3155 + 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>');
3156 + x += '<div id=aginsTypeDiv>';
3157 + 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>');
3158 + x += '</div><hr>';
3159 +
3160 + // \/:*?"<>|
3161 + var meshfilename = mesh.name
3162 + meshfilename = meshfilename.split('\\').join('').split('/').join('').split(':').join('').split('*').join('').split('?').join('').split('"').join('').split('<').join('').split('>').join('').split('|').join('').split(' ').join('').split('\'').join('');
3163 +
3164 + // Windows agent install
3165 + //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 />";
3166 + x += '<div id=agins_windows>' + format("To add a new computer to device group \"{0}\", download the mesh agent and install it the computer to manage. This agent has server and device group information embedded within it.", EscapeHtml(mesh.name)) + '<br /><br />';
3167 + 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)>');
3168 + 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)>');
3169 + if (debugmode > 0) { x += addHtmlValue("Settings File", '<a id=aginswmshlnk href="meshsettings?id=' + meshid.split('/')[2] + '&installflags=0" rel="noreferrer noopener" target="_blank">' + format("{0} settings (.msh)", EscapeHtml(mesh.name)) + '</a>'); }
3170 + x += '</div>';
3171 +
3172 + // Linux agent install
3173 + x += '<div id=agins_linux style=display:none>' + format("To add a computer to {0} run the following command. Root credentials will be needed.", EscapeHtml(mesh.name)) + '<br />';
3174 + 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>';
3175 + x += '<div style=\'font-size:x-small\'>' + "* For BSD, run \"pkg install wget sudo bash\" first." + '</div></div>';
3176 +
3177 + // MacOS agent install
3178 + x += '<div id=agins_osx style=display:none>' + format("To add a new computer to device group \"{0}\", download the mesh agent and install it the computer to manage. This agent installer has server and device group information embedded within it.", EscapeHtml(mesh.name)) + '<br /><br />';
3179 + 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)>');
3180 + x += '</div>';
3181 +
3182 + // Windows agent uninstall
3183 + 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 />';
3184 + x += addHtmlValue("Mesh Agent", '<a href="meshagents?id=3" download onclick="setDialogMode(0)" title="' + "32bit version of the MeshAgent" + '">' + "Windows (.exe)" + '</a>');
3185 + x += addHtmlValue("Mesh Agent", '<a href="meshagents?id=4" download onclick="setDialogMode(0)" title="' + "64bit version of the MeshAgent" + '">' + "Windows x64 (.exe)" + '</a>');
3186 + x += '</div>';
3187 +
3188 + // Linux agent uninstall
3189 + x += '<div id=agins_linux_un style=display:none>' + "To remove a mesh agent, run the following command. Root credentials will be needed." + '<br />';
3190 + 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>';
3191 + x += '</div>';
3192 +
3193 + setDialogMode(2, "Add Mesh Agent", 2, null, x, 'fileDownload');
3194 + var servername = serverinfo.name;
3195 + 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.
3196 + var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
3197 +
3198 + if (serverinfo.https == true)
3199 + {
3200 + var portStr = (serverinfo.port == 443)?'':(':' + serverinfo.port);
3201 + if ((features & 0x2000) == 0)
3202 + {
3203 + 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 -E ./meshinstall.sh https://' + servername + portStr + domainUrlNoSlash + ' \'' + meshid.split('/')[2] + '\'\r\n';
3204 + 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';
3205 + }
3206 + else
3207 + {
3208 + // Server asked that agent be installed to preferably not use a HTTP proxy.
3209 + 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';
3210 + 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';
3211 + }
3212 + }
3213 + else
3214 + {
3215 + var portStr = (serverinfo.port == 80) ? '' : (':' + serverinfo.port);
3216 + if ((features & 0x2000) == 0)
3217 + {
3218 + 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 -E ./meshinstall.sh http://' + servername + portStr + domainUrlNoSlash + ' \'' + meshid.split('/')[2] + '\'\r\n';
3219 + 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';
3220 + }
3221 + else
3222 + {
3223 + // Server asked that agent be installed to preferably not use a HTTP proxy.
3224 + 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';
3225 + 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';
3226 + }
3227 + }
3228 + Q('aginsSelect').focus();
3229 + addAgentToMeshClick();
3230 + return false;
3231 + }
3232 +
3233 + function copyAgentUrl(url,addflag) {
3234 + var servername = serverinfo.name;
3235 + 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.
3236 + var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
3237 + var portStr = (serverinfo.port == 443) ? '' : (':' + serverinfo.port);
3238 + var c = 'https://' + servername + portStr + domainUrl + url;
3239 + if (addflag == 1) c += Q('aginsType').value;
3240 + copyTextToClip(c);
3241 + }
3242 +
3243 + function addAgentToMeshClick() {
3244 + var v = Q('aginsSelect').value;
3245 + QV('agins_windows', v == 0);
3246 + QV('agins_linux', v == 1);
3247 + QV('agins_osx', v == 2);
3248 + QV('agins_windows_un', v == 3);
3249 + QV('agins_linux_un', v == 4);
3250 + QV('aginsTypeDiv', v == 0);
3251 +
3252 + // Fix the links if needed
3253 + Q('aginsw32lnk').href = (Q('aginsw32lnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value;
3254 + Q('aginsw64lnk').href = (Q('aginsw64lnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value;
3255 + if (debugmode > 0) { Q('aginswmshlnk').href = (Q('aginswmshlnk').href.split('installflags=')[0]) + 'installflags=' + Q('aginsType').value; }
3256 + }
3257 +
3258 + function validateDeviceToMesh() {
3259 + QE('idx_dlgOkButton', (Q('dp1devicename').value.length > 0) && (passwordcheck(Q('dp1password').value)));
3260 + }
3261 +
3262 + function addDeviceToMeshEx(button, meshid) {
3263 + var amtuser = Q('dp1username').value;
3264 + if (amtuser == '') amtuser = 'admin';
3265 + var host = Q('dp1hostname').value;
3266 + if (host == '') host = Q('dp1devicename').value;
3267 + meshserver.send({ action: 'addamtdevice', meshid: meshid, devicename: Q('dp1devicename').value, hostname: host, amtusername: amtuser, amtpassword: Q('dp1password').value, amttls: Q('dp1tls').value });
3268 + }
3269 +
3270 + function deviceHeaderSet() {
3271 + if (deviceHeaderId == 0) { deviceHeaderId = 1; return; }
3272 + deviceHeaders['DevxHeader' + deviceHeaderId] = deviceHeaderTotal + ((deviceHeaderTotal == 1) ? "nœud" : "noeuds");
3273 + //var title = '';
3274 + //for (x in deviceHeaderCount) { if (title.length > 0) title += ', '; title += deviceHeaderCount[x] + ' ' + PowerStateStr2(x); }
3275 + //deviceHeadersTitles["DevxHeader" + deviceHeaderId] = title;
3276 + deviceHeaderId++;
3277 + deviceHeaderCount = {};
3278 + deviceHeaderTotal = 0;
3279 + }
3280 +
3281 + 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>'];
3282 + 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"];
3283 + var powerColorTable = ['pwsTransparent', 'pwsBlack', 'pwsBlue', 'pwsBlue2', 'pwsLightblue', 'pwsBlueviolet', 'pwsDarkgreen', 'pwsLightseagreen', 'pwsLightseagreen2'];
3284 + function NodeStateStr(node) {
3285 + var states = [];
3286 + if (node.state > 0 && node.state < powerStatetable.length) state.push(powerStatetable[node.state]);
3287 + if (node.conn) {
3288 + if ((node.conn & 1) != 0) { states.push('<span title=\"' + "Mesh agent is connected and ready for use." + '\">' + "Agent" + '</span>'); }
3289 + if ((node.conn & 2) != 0) { states.push('<span title=\"' + "Intel&reg; AMT CIRA is connected and ready for use." + '\">' + "CIRA" + '</span>'); }
3290 + else if ((node.conn & 4) != 0) { states.push('<span title=\"' + "Intel&reg; AMT is routable." + '\">' + "AMT" + '</span>'); }
3291 + if ((node.conn & 8) != 0) { states.push('<span title=\"' + "Mesh agent is reachable using another agent as relay." + '\">' + "Relay" + '</span>'); }
3292 + if ((node.conn & 16) != 0) { states.push('<span title=\"' + "MQTT connection to the device is active." + '\">' + "MQTT" + '</span>'); }
3293 + }
3294 + if ((node.pwr != null) && (node.pwr != 0)) { states.push(powerStateStrings[node.pwr]); }
3295 + return states.join(', ');
3296 + }
3297 +
3298 + function PowerStateStr(x) {
3299 + if (x < powerStatetable.length) return powerStatetable[x];
3300 + return '';
3301 + }
3302 +
3303 + function PowerStateStr2(x) {
3304 + if ((x != 0) && (x < powerStatetable.length)) return powerStatetable[x];
3305 + return "Inconnue";
3306 + }
3307 +
3308 + function selectallButtonFunction() {
3309 + var elements = document.getElementsByClassName('DeviceCheckbox'), checkcount = 0;
3310 + for (var i=0;i<elements.length;i++) { if (elements[i].checked === true) checkcount++; }
3311 + for (var i=0;i<elements.length;i++) { elements[i].checked = (checkcount == 0); }
3312 + p1updateInfo();
3313 + }
3314 +
3315 + function p1updateInfo() {
3316 + var elements = document.getElementsByClassName('DeviceCheckbox'), checkcount = 0;
3317 + for (var i=0;i<elements.length;i++) { if (elements[i].checked === true) { checkcount++; } }
3318 + if (checkcount > 0) {
3319 + QE('GroupActionButton', true);
3320 + Q('SelectAllButton').value = "Select None";
3321 + QV('cxmgroupsplit', true);
3322 + QV('cxmdesktop', true);
3323 + } else {
3324 + QE('GroupActionButton', false);
3325 + Q('SelectAllButton').value = "Select All";
3326 + QV('cxmgroupsplit', false);
3327 + QV('cxmdesktop', false);
3328 + }
3329 + }
3330 +
3331 + function groupActionFunction() {
3332 + var mqttx = '';
3333 + if (features & 0x00400000) { // Check if any of the selected devices have a MQTT connection active
3334 + var nodeids = getCheckedDevices();
3335 + for (var i in nodeids) { if ((getNodeFromId(nodeids[i]).conn & 16) != 0) { mqttx = '<option value=103>' + "Send MQTT Message" + '</option>'; } }
3336 + }
3337 + var x = "Select an operation to perform on all selected devices. Actions will be performed only with proper rights." + '<br /><br />';
3338 + 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>' + mqttx + '<option value=101>' + "Delete devices" + '</option></select>');
3339 + setDialogMode(2, "Group Action", 3, groupActionFunctionEx, x);
3340 + }
3341 +
3342 + // Get the list of checked devices, removes any duplicates.
3343 + function getCheckedDevices() {
3344 + var nodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
3345 + 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); } } } }
3346 + return nodeids;
3347 + }
3348 +
3349 + function groupActionFunctionEx() {
3350 + var op = Q('d2groupop').value;
3351 + if (op == 100) {
3352 + // Group wake
3353 + meshserver.send({ action: 'wakedevices', nodeids: getCheckedDevices() });
3354 + } else if (op == 101) {
3355 + // Group delete, ask for confirmation
3356 + var x = "Confirm delete selected devices(s)?" + '<br /><br />';
3357 + x += '<label><input id=d2check type=checkbox onchange=d2groupActionFunctionDelEx() />' + "Confirm" + '</label>';
3358 + setDialogMode(2, "Delete Nodes", 3, groupActionFunctionDelEx, x);
3359 + QE('idx_dlgOkButton', false);
3360 + } else if (op == 102) {
3361 + // Move computers to a different group
3362 + p10showChangeGroupDialog(getCheckedDevices());
3363 + } else if (op == 103) {
3364 + // Send MQTT Message
3365 + p10showSendMqttMsgDialog(getCheckedDevices());
3366 + } else {
3367 + // Power operation
3368 + meshserver.send({ action: 'poweraction', nodeids: getCheckedDevices(), actiontype: parseInt(op) });
3369 + }
3370 + }
3371 +
3372 + function d2groupActionFunctionDelEx() { QE('idx_dlgOkButton', Q('d2check').checked); }
3373 + function groupActionFunctionDelEx() { meshserver.send({ action: 'removedevices', nodeids: getCheckedDevices() }); }
3374 +
3375 + function onSortSelectChange(skipsave) {
3376 + sort = document.getElementById('sortselect').selectedIndex;
3377 + if (!skipsave) { putstore('sort', sort); }
3378 + }
3379 +
3380 + 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; }
3381 + 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; }
3382 + function deviceSort(a, b) { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; }
3383 + function deviceHostSort(a, b) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; }
3384 + function onSearchFocus(x) { searchFocus = x; }
3385 + function onMapSearchFocus(x) { mapSearchFocus = x; }
3386 + function onUserSearchFocus(x) { userSearchFocus = x; }
3387 + function onConsoleFocus(x) { consoleFocus = x; }
3388 +
3389 + function onSearchInputChanged() {
3390 + var x = Q('SearchInput').value.toLowerCase().trim(); putstore('_search', x);
3391 + var userSearch = null, ipSearch = null, groupSearch = null;
3392 + if (x.startsWith('user:')) { userSearch = x.substring(5); }
3393 + else if (x.startsWith('u:')) { userSearch = x.substring(2); }
3394 + else if (x.startsWith('ip:')) { ipSearch = x.substring(3); }
3395 + else if (x.startsWith('group:')) { groupSearch = x.substring(6); }
3396 + else if (x.startsWith('g:')) { groupSearch = x.substring(2); }
3397 +
3398 + if (x == '') {
3399 + // No search
3400 + for (var d in nodes) { nodes[d].v = true; }
3401 + } else if (ipSearch != null) {
3402 + // IP address search
3403 + for (var d in nodes) { nodes[d].v = ((nodes[d].ip != null) && (nodes[d].ip.indexOf(ipSearch) >= 0)); }
3404 + } else if (groupSearch != null) {
3405 + // Group filter
3406 + for (var d in nodes) { nodes[d].v = (meshes[nodes[d].meshid].name.toLowerCase().indexOf(groupSearch) >= 0); }
3407 + } else if (userSearch != null) {
3408 + // User search
3409 + for (var d in nodes) {
3410 + nodes[d].v = false;
3411 + 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; } } }
3412 + }
3413 + } else {
3414 + // Device name search
3415 + try {
3416 + var rs = x.split(/\s+/).join('|'), rx = new RegExp(rs); // In some cases (like +), this can throw an exception.
3417 + for (var d in nodes) {
3418 + nodes[d].v = (rx.test(nodes[d].name.toLowerCase())) || (nodes[d].rnamel != null && rx.test(nodes[d].rnamel.toLowerCase()));
3419 + if ((nodes[d].v == false) && nodes[d].tags) {
3420 + for (var s in nodes[d].tags) {
3421 + if (rx.test(nodes[d].tags[s].toLowerCase())) {
3422 + nodes[d].v = true;
3423 + break;
3424 + } else {
3425 + nodes[d].v = false;
3426 + }
3427 + }
3428 + }
3429 + }
3430 + } catch (ex) { for (var d in nodes) { nodes[d].v = true; } }
3431 + }
3432 + }
3433 +
3434 + var contextelement = null;
3435 + function handleContextMenu(event) {
3436 + hideContextMenu();
3437 + var scrollLeft = (window.pageXOffset !== null) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
3438 + var scrollTop = (window.pageYOffset !== null) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
3439 + var elem = document.elementFromPoint(event.pageX - scrollLeft, event.pageY - scrollTop);
3440 + if (elem && elem != null && elem.id == 'connectbutton2' && currentNode && currentNode.agent && (currentNode.agent.id > 0) && (currentNode.agent.id < 5)) {
3441 + contextelement = elem;
3442 + var contextmenudiv = document.getElementById('termShellContextMenu');
3443 + contextmenudiv.style.left = event.pageX + 'px';
3444 + contextmenudiv.style.top = event.pageY + 'px';
3445 + contextmenudiv.style.display = 'block';
3446 + } else if (elem && elem != null && elem.id == 'MxMESH') {
3447 + contextelement = elem;
3448 + var contextmenudiv = document.getElementById('meshContextMenu');
3449 + contextmenudiv.style.left = event.pageX + 'px';
3450 + contextmenudiv.style.top = event.pageY + 'px';
3451 + contextmenudiv.style.display = 'block';
3452 + } else {
3453 + while (elem && elem != null && elem.id != 'devs') { elem = elem.parentElement; }
3454 + if (!elem || elem == null) return true;
3455 + contextelement = elem;
3456 + var contextmenudiv = document.getElementById('contextMenu');
3457 + contextmenudiv.style.left = event.pageX + 'px';
3458 + contextmenudiv.style.top = event.pageY + 'px';
3459 + contextmenudiv.style.display = 'block';
3460 +
3461 + // Get the node and set the menu options
3462 + var nodeid = contextelement.children[1].attributes.onclick.value;
3463 + var node = getNodeFromId(nodeid.substring(12, nodeid.length - 18));
3464 + var mesh = meshes[node.meshid];
3465 + var meshlinks = mesh.links[userinfo._id];
3466 + var meshrights = meshlinks.rights;
3467 + var consoleRights = ((meshrights & 16) != 0);
3468 +
3469 + // Check if we have terminal and file access
3470 + var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0));
3471 + var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0));
3472 +
3473 + 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)));
3474 + 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);
3475 + QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess);
3476 + QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8));
3477 + QV('cxconsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
3478 + }
3479 +
3480 + return haltEvent(event);
3481 + }
3482 +
3483 + function cmaction(action,event) {
3484 + var nodeid = contextelement.children[1].attributes.onclick.value;
3485 + nodeid = nodeid.substring(12, nodeid.length - 18);
3486 + if (action == 7) { Q('viewselect').value = 3; Q('viewselect').onchange(); Q('autoConnectDesktopCheckbox').checked = true; Q('autoConnectDesktopCheckbox').onclick(); } // Multi-Desktop
3487 + if ((action > 0) && (action < 7)) {
3488 + var panel = [0, 10, 12, 11, 13, 16, 15][action]; // (invalid), General, Desktop, Terminal, Files, Events, Console
3489 + if (event && (event.shiftKey == true)) {
3490 + // Open the device in a different tab
3491 + window.open(window.location.origin + '?node=' + nodeid.split('/')[2] + '&viewmode=' + panel + '&hide=16', 'meshcentral:' + nodeid);
3492 + } else {
3493 + // Go to the right panel
3494 + gotoDevice(nodeid, panel);
3495 +
3496 + // If possible, connect...
3497 + var mesh = meshes[currentNode.meshid];
3498 + if ((currentNode.conn & 1) && (mesh.mtype == 2)) {
3499 + if ((panel == 11) && (desktop == null) && (currentNode.agent.caps & 1)) { connectDesktop(null, 1); } // Desktop
3500 + if ((panel == 12) && (terminal == null) && (currentNode.agent.caps & 2)) { connectTerminal(null, 1); } // Terminal
3501 + if ((panel == 13) && (files == null)) { connectFiles(null); } // files
3502 + }
3503 + }
3504 + }
3505 + }
3506 +
3507 + function cmmeshaction(action) {
3508 + var meshid = contextelement.attributes.onclick.value.substring(10, contextelement.attributes.onclick.value.length - 2);
3509 + var elements = document.getElementsByClassName('DeviceCheckbox');
3510 + if ((action == 1) || (action == 2)) {
3511 + for (var i = 0; i < elements.length; i++) {
3512 + if ((elements[i].attributes) && (elements[i].attributes['class']['value'].split(' ')[0] == meshid)) { elements[i].checked = (action == 1); }
3513 + }
3514 + }
3515 + //if (action == 3) { window.location = "multidesktop.aspx?mesh=" + meshid + "&auto=1"; }
3516 + p1updateInfo();
3517 + }
3518 +
3519 + function cmtermaction(action) {
3520 + connectTerminal(null, 1, { powershell: (action == 2) });
3521 + }
3522 +
3523 + function hideContextMenu() {
3524 + QV('contextMenu', false);
3525 + QV('meshContextMenu', false);
3526 + QV('termShellContextMenu', false);
3527 + contextelement = null;
3528 + }
3529 +
3530 + //
3531 + // DEVICES MAP
3532 + //
3533 +
3534 + // Maps code starts from here. Initialize all the variables
3535 + var xxmap = {
3536 + map: null,
3537 + contextmenu: null,
3538 + activeInteractions: [], // Save Modified features in this list
3539 + showindex: 0,
3540 + markersSource: null, // Initialize a Source Vector
3541 + markersLayer: null,
3542 + mapLayer: null, // Create a tile and use OSM source
3543 + mapView: null, // Sets the initial view
3544 + }
3545 +
3546 + // Add a feature for every Node and change style if connection status changes
3547 + function updateMapMarkers(selectedMesh) {
3548 + if ((xxmap != null) && (xxmap.map == null)) { try { loadmap(); } catch (ex) { console.error('loadmap() exception', ex); } }
3549 + if (xxmap == null) return;
3550 + var boundingBox = null;
3551 + for (var i in nodes) {
3552 + try {
3553 + var loc = map_parseNodeLoc(nodes[i]), feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
3554 + if ((loc != null) && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
3555 + var lat = loc[0], lon = loc[1], type = loc[2];
3556 + 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; } }
3557 + if (feature == null) { addFeature(nodes[i]); boundingBox[4] = 1; } else { updateFeature(nodes[i], feature); feature.setStyle(markerStyle(nodes[i], loc[2])); } // Update Feature
3558 + } else {
3559 + if (feature) { xxmap.markersSource.removeFeature(feature); }
3560 + }
3561 + } catch (ex) { console.error('updateMapMarkers() exception', ex, JSON.stringify(nodes[i])); }
3562 + }
3563 + return boundingBox;
3564 + }
3565 +
3566 + // Show node details on hovering over a feature
3567 + var map_cm_popup = new ol.Overlay({ element: Q('xmap-info-window'), positioning: 'bottom-center', stopEvent: false });
3568 +
3569 + // Edit Marker item
3570 + var map_cm_editMarker = { text: "Modify node location", callback: function (obj) { modifyMarkerloc(obj.data); } };
3571 +
3572 + // Clear Marker item
3573 + var map_cm_clearMarker = { text: "Remove node location", callback: function (obj) {
3574 + meshserver.send({ action: 'changedevice', nodeid: obj.data.a, userloc: [] }); // Clear the user position marker
3575 + }};
3576 +
3577 + // Save Marker item
3578 + var map_cm_saveMarker = { text: "Save node location", callback: function (obj) { saveMarkerloc(obj.data); } };
3579 +
3580 + // Build a context menu for a feature
3581 + var map_cm_nodemenu_items = [
3582 + { text: "General information", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 10); } } },
3583 + { text: "Desktop", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 11); } } },
3584 + { text: "Terminal", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 12); } } },
3585 + { text: "Intel&reg; AMT", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 14); } } },
3586 + '-',
3587 + { text: "Zoom-in to extent", callback: function(obj) { var coords = obj.data.getGeometry().getCoordinates(); zoomToLocation(coords, 19); } },
3588 + { text: "Zoom-out to extent", callback: function(obj) { var coords = obj.data.getGeometry().getCoordinates(); zoomToLocation(coords, 2); } }
3589 + ];
3590 +
3591 + // Context menu for clicks other than on feature
3592 + var contextmenu_items = [
3593 + { text: "Refresh", callback: function () { refreshMap(true, true); } },
3594 + { text: "Zoom to fit extent", callback: function () { zoomToFitExtent(); } },
3595 + { text: "Centré la carte ici", callback: function(obj) { xxmap.mapView.animate({ center: obj.coordinate } ); } },
3596 + { text: "Place node here", callback: function(obj) { placeNode(obj.coordinate); } }
3597 + ];
3598 +
3599 + function stringToIntHash(str) {
3600 + var hash = 0, i;
3601 + for (i = 0; i < str.length; i++) { hash = ((hash << 5) - hash) + str.charCodeAt(i); hash |= 0; }
3602 + return hash;
3603 + };
3604 +
3605 + // Get the lat/lon from a node
3606 + function map_parseNodeLoc(node) {
3607 + var loc = null, t = 0;
3608 + if (node.iploc) { loc = node.iploc; t = 1; }
3609 + if (node.wifiloc) { loc = node.wifiloc; t = 2; }
3610 + if (node.gpsloc) { loc = node.gpsloc; t = 3; }
3611 + if (node.userloc) { loc = node.userloc; t = 4; }
3612 + if ((loc == null) || (typeof loc != 'string')) return null;
3613 + loc = loc.split(',');
3614 + if (t == 1) {
3615 + // If this is IP location, randomize the position a little.
3616 + return [ parseFloat(loc[0]) + (stringToIntHash(node._id.substring(0, 20)) / 100000000000), parseFloat(loc[1]) + (stringToIntHash(node._id.substring(20)) / 100000000000), t ];
3617 + } else {
3618 + // Return the real position
3619 + return [ parseFloat(loc[0]), parseFloat(loc[1]), t ];
3620 + }
3621 + }
3622 +
3623 + // Load the entire map
3624 + function loadmap() {
3625 + if (xxmap == null) return;
3626 + if ((features & 0x8000) == 0) { QV('viewselectmapoption', false); QV('devViewButton4', false); xxmap = null; return; } // Geolocation not supported
3627 + try {
3628 + // Initialize a Source Vector
3629 + xxmap.markersSource = new ol.source.Vector();
3630 +
3631 + xxmap.markersLayer = new ol.layer.Vector({
3632 + source: xxmap.markersSource
3633 + });
3634 +
3635 + // Create a tile and use OSM source
3636 + xxmap.mapLayer = new ol.layer.Tile({ source: new ol.source.OSM() });
3637 +
3638 + xxmap.mapView = new ol.View({ // Set the initial view
3639 + center: ol.proj.transform([0, 0], 'EPSG:4326', 'EPSG:3857'),
3640 + zoom: 2,
3641 + minZoom: 2,
3642 + maxZoom: 20,
3643 + extent: ol.proj.transformExtent([-100000, -69.55, 100000, 69.55], 'EPSG:4326', 'EPSG:3857')
3644 + });
3645 +
3646 + xxmap.map = new ol.Map({
3647 + target: 'xdevicesmap',
3648 + layers: [xxmap.mapLayer, xxmap.markersLayer],
3649 + view: xxmap.mapView
3650 + });
3651 +
3652 + xxmap.map.addOverlay(map_cm_popup);
3653 +
3654 + // Goto information tab if a user clicks on a feature
3655 + xxmap.map.on('click', function(evt) {
3656 + var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(feat, layer) { return feat; });
3657 + if (feature) {
3658 + var nodeid = feature.getId();
3659 + if (nodeid != null) { gotoDevice(nodeid, 10); } // Goto general info tab
3660 + else { // For pointer
3661 + var nodeFeatgoto = getCorrespondingFeature(feature); gotoDevice(nodeFeatgoto.getId(), 10);
3662 + }
3663 + }
3664 + });
3665 +
3666 + // On hover feature show the name of the node. Also add pointer style
3667 + xxmap.map.on('pointermove', function(evt) {
3668 + var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(feat, layer) { return feat; });
3669 + if (feature) {
3670 + xxmap.map.getTargetElement().style.cursor = 'pointer';
3671 + var coord = feature.getGeometry().getCoordinates();
3672 + // map_cm_popup.setPosition(evt.coordinate);
3673 + map_cm_popup.setPosition(coord);
3674 + var featid = feature.getId();
3675 + if (featid) {
3676 + QH('xmap-info-window', feature.get('name'));
3677 + } else {
3678 + var nodeFeat = getCorrespondingFeature(feature); // Return the node feature associated to pointer.
3679 + QH('xmap-info-window', nodeFeat.get('name'));
3680 + }
3681 + } else {
3682 + xxmap.map.getTargetElement().style.cursor = '';
3683 + QH('xmap-info-window', '');
3684 + }
3685 + });
3686 +
3687 + // Initialize context menu for openlayers
3688 + var contextmenu = new ContextMenu({
3689 + width: 160,
3690 + defaultItems: false, // defaultItems are Zoom In/Zoom Out
3691 + items: contextmenu_items
3692 + });
3693 +
3694 + // On right click open the context menu
3695 + contextmenu.on("open", function (evt) {
3696 + var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(ft, l){ return ft; });
3697 + xxmap.contextmenu.clear(); //Clear the context menu
3698 + if (feature) {
3699 + var featId = feature.getId();
3700 + if (featId) { addContextMenuItems(feature); } // Node feature will have an id
3701 + else { // If the feature is a pointer, Get its corresponding Node feature
3702 + var nodeFeature = getCorrespondingFeature(feature); //return the node feature associated to pointer.
3703 + if (nodeFeature) { addContextMenuItems(nodeFeature); }
3704 + else{ xxmap.contextmenu.extend(contextmenu_items); }
3705 + }
3706 + }
3707 + else { xxmap.contextmenu.extend(contextmenu_items); }
3708 + });
3709 + if (xxmap.contextmenu == null) { xxmap.contextmenu = contextmenu; }
3710 + xxmap.map.addControl(xxmap.contextmenu);
3711 + //addMeshOptions(); // Adds Mesh names to mesh dropdown
3712 + } catch (ex) {
3713 + console.log(ex);
3714 + QV('viewselectmapoption', false);
3715 + QV('devViewButton4', false);
3716 + xxmap = null;
3717 + }
3718 + }
3719 +
3720 + // Add feature on to Map for a Node
3721 + function addFeature(node, lat, lon) {
3722 + var existingfeature = getModifiedFeature(node._id); // Check if Corresponding feature was Modified ( Modifed feature are in active interactions list)
3723 + if (existingfeature) { xxmap.markersSource.addFeature(existingfeature); } // Add that existing feature
3724 + else { // Add new feature for this node
3725 + if (!lat && !lon) { var loc = map_parseNodeLoc(node); lat = loc[0]; lon = loc[1]; }
3726 +
3727 + // 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.
3728 + if (lon > 180) { lon = 180 - lon; meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: [ lat, lon ] }); }
3729 +
3730 + if ((lat < 90) && (lat > -90) && (lon < 180) && (lon > -180)) { // Check valid lat/lon
3731 + 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 });
3732 + feature.setId(node._id); // Set id for the device as nodeid
3733 + feature.setStyle(markerStyle(node));
3734 + xxmap.markersSource.addFeature(feature); // Add the feature to Marker Source
3735 + }
3736 + }
3737 + }
3738 +
3739 + // Removing any feature from map
3740 + function removeFeature(node) {
3741 + var feature = xxmap.markersSource.getFeatureById(node._id);
3742 + if (feature) { xxmap.markersSource.removeFeature(feature); }
3743 + }
3744 +
3745 + // Update feature
3746 + function updateFeature(node, feature) {
3747 + if (node.conn != feature.get('status') ) { // Update status if changed
3748 + feature.set('status',node.conn)
3749 + feature.setStyle(markerStyle(node));
3750 + }
3751 +
3752 + // Since this is IP address location, add some fixed randomness to the location. Avoid pin pile-up.
3753 + var loc = map_parseNodeLoc(node);
3754 + if (loc != null) {
3755 + var lat = loc[0], lon = loc[1];
3756 + if ((lat != feature.get('lat')) || (lon != feature.get('lon'))) { // Update lat and lon if changed
3757 + feature.set('lat', lat); feature.set('lon', lon);
3758 + var modifiedCoordinates = ol.proj.transform([parseFloat(lon), parseFloat(lat)], 'EPSG:4326', 'EPSG:3857');
3759 + feature.getGeometry().setCoordinates(modifiedCoordinates);
3760 + }
3761 + }
3762 +
3763 + if (node.name != feature.get('name') ) { feature.set('name', node.name); } // Update name
3764 + }
3765 +
3766 + // Enable dragging of a marker after edit option is clicked in context menu
3767 + function modifyMarkerloc(ft){
3768 + var featid = ft.getId();
3769 + if (featid) {
3770 + ft.setStyle(markerStyle(getNodeFromId(ft.a), 4)); // Switch to a user marker
3771 + if ( !getActiveInteractions(ft)) {
3772 + var dragInteration = new ol.interaction.Modify({
3773 + features: new ol.Collection([ft]),
3774 + pixelTolerance: 10
3775 + });
3776 + xxmap.activeInteractions.push({ featureid: featid, feature:ft, interaction: dragInteration }); // Also keep track of Interactions
3777 + xxmap.map.addInteraction(dragInteration);
3778 + }
3779 + }
3780 + }
3781 +
3782 + // This will be called when save location option is clicked in context menu
3783 + function saveMarkerloc(ft){
3784 + var featid = ft.getId()
3785 + if (featid) {
3786 + var actInteraction = getActiveInteractions(ft);
3787 + if (actInteraction) { // Check if the interaction exists
3788 + xxmap.map.removeInteraction(actInteraction); //Clear Interaction for that node
3789 + removeInteraction(featid);
3790 + var coord = ft.getGeometry().getCoordinates();
3791 + var v = ol.proj.transform(coord, 'EPSG:3857', 'EPSG:4326');
3792 + if (v[0] > 180) { v[0] = 180 - v[0]; }
3793 + var vx = [ v[1], v[0] ]; // Flip the coordinates around, lat/long
3794 + meshserver.send({ action: 'changedevice', nodeid: featid, userloc: vx }); // Send them to server to save changes
3795 + }
3796 + }
3797 + }
3798 +
3799 + // Style the Markers
3800 + function markerStyle(node, type) {
3801 + if (type == null) {
3802 + type = 0;
3803 + if (node.iploc) { type = 1; }
3804 + if (node.wifiloc) { type = 2; }
3805 + if (node.gpsloc) { type = 3; }
3806 + if (node.userloc) { type = 4; }
3807 + }
3808 + var types = ['', '-ip','-wifi','-gps','-user'];
3809 + var color = connStateColor(node);
3810 + var style = new ol.style.Style({
3811 + image: new ol.style.Icon({ color: color, anchor: [0.5, 1], src: 'images/mapmarker' + types[type] + '.png' })
3812 + //stroke: new ol.style.Stroke({ color: '#000', width: 20 })
3813 + //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 }) })
3814 + });
3815 +
3816 + /*
3817 + deviceMark.setStyle(new ol.style.Style({
3818 + text: new ol.style.Text({
3819 + //font: '12px helvetica,sans-serif',
3820 + text: currentNode.name,
3821 + textAlign: 'right',
3822 + offsetX: -10,
3823 + fill: new ol.style.Fill({ color: '#000' }),
3824 + stroke: new ol.style.Stroke({ color: '#fff', width: 2 })
3825 + }),
3826 + image: new ol.style.Icon(({ color: [113, 140, 0], src: 'images/dot.png' })) }));
3827 + */
3828 +
3829 + return [ style ];
3830 + }
3831 +
3832 + // TODO: Add more connection status types. Currently we only change color if connection status changes
3833 + function connStateColor(nodeConn){
3834 + if (nodeConn.conn == 1 || nodeConn.conn == 3 || nodeConn.conn == 5) { return '#00ffdd'; } // Green for connected devices
3835 + return '#C70039'; // Red if the Agent is not connected
3836 + }
3837 +
3838 + // Add save/edit option to context menu
3839 + function addContextMenuItems(feature) {
3840 + if (getActiveInteractions(feature)) { // If this feature is modified then display save option in contextmenu
3841 + map_cm_saveMarker.data = feature;
3842 + xxmap.contextmenu.push(map_cm_saveMarker);
3843 + } else {
3844 + map_cm_editMarker.data = feature;
3845 + xxmap.contextmenu.push(map_cm_editMarker);
3846 + var node = getNodeFromId(feature.a);
3847 + if (node.userloc) {
3848 + map_cm_clearMarker.data = feature;
3849 + xxmap.contextmenu.push(map_cm_clearMarker);
3850 + }
3851 + }
3852 + map_cm_nodemenu_items.forEach(function (item){
3853 + if (item.text == "Zoom-in to extent" || item.text == "Zoom-out to extent") { item.data = feature; }
3854 + else { if (item != '-') { item.data = feature.getId(); } }
3855 + });
3856 + xxmap.contextmenu.extend(map_cm_nodemenu_items);
3857 + }
3858 +
3859 + // Return a active Interaction if it exists in activeInteractions list
3860 + function getActiveInteractions(feature) {
3861 + var featid = feature.getId();
3862 + for (var i = 0; i < xxmap.activeInteractions.length; i++) {
3863 + if (xxmap.activeInteractions[i].featureid == featid) { return xxmap.activeInteractions[i].interaction; }
3864 + }
3865 + return false;
3866 + }
3867 +
3868 + // Return Modified feature based on Id
3869 + function getModifiedFeature(featid) {
3870 + if (featid) {
3871 + for (var i = 0; i < xxmap.activeInteractions.length; i++) {
3872 + if (xxmap.activeInteractions[i].featureid == featid) { return xxmap.activeInteractions[i].feature; }
3873 + }
3874 + }
3875 + return null;
3876 + }
3877 +
3878 + // Remove Interaction
3879 + function removeInteraction(ftid) {
3880 + var index = -1;
3881 + for (var i = 0; i < xxmap.activeInteractions.length; i++) {
3882 + if (xxmap.activeInteractions[i].featureid === ftid) { index = i; break; }
3883 + }
3884 + if (index >= 0) { xxmap.activeInteractions.splice(index, 1); }
3885 + }
3886 +
3887 + // Check if pointer coordinates are equal to features and return node feature
3888 + function getCorrespondingFeature(pointerFeat) {
3889 + var pointerCoord = pointerFeat.getGeometry().getCoordinates();
3890 + for (var i = 0; i < xxmap.activeInteractions.length ; i++) {
3891 + var modifiedFeatures = xxmap.activeInteractions[i].feature;
3892 + var fearCoord = modifiedFeatures.getGeometry().getCoordinates();
3893 + if (fearCoord[0].toFixed(5) == pointerCoord[0].toFixed(5) && fearCoord[1].toFixed(5) == pointerCoord[1].toFixed(5) ) { return modifiedFeatures; }
3894 + }
3895 + return null;
3896 + }
3897 +
3898 + // Refresh the map and clear list
3899 + function refreshMap(reset, rebound){
3900 + if (reset) {
3901 + xxmap.map.setTarget(null);
3902 + xxmap.map = null;
3903 + xxmap.markersSource = null;
3904 + xxmap.mapView = null;
3905 + xxmap.mapLayer = null;
3906 + xxmap.activeInteractions = []; // Clear Active Interaction list
3907 + }
3908 + //clearMeshOptions();
3909 + //onSelectMeshChange();
3910 + var box = updateMapMarkers();
3911 + if ((box != null) && (rebound || (box[4] == 1))) {
3912 + var clat = (box[0] + box[2]) / 2;
3913 + var clon = (box[1] + box[3]) / 2;
3914 + var cscale = Math.max(Math.abs(box[0] - box[2]), Math.abs(box[1] - box[3]));
3915 + var view = xxmap.map.getView();
3916 + view.setCenter(ol.proj.transform([clon, clat], 'EPSG:4326', 'EPSG:3857'));
3917 + var i = 360, j = -2;
3918 + while (i > cscale) { j++; i = i / 2; }
3919 + view.setZoom(j);
3920 + }
3921 + }
3922 +
3923 + // Called When Place a node option is clicked from context menu
3924 + function placeNode(coords) {
3925 + if (xxdialogMode) return;
3926 + var x = '<div style=margin-bottom:6px><label for=selectnode-search>Search</label>&nbsp&nbsp<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>';
3927 + for (var i in nodes) {
3928 + 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 />';
3929 + 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>';
3930 + }
3931 + setDialogMode(2, "Select a node to place", 3, placeNodeEx, x + '</div>', coords);
3932 + onPlaceNodeInputChange();
3933 + }
3934 +
3935 + function placeNodeEx(button, coords) {
3936 + var elements = document.getElementsByName('PlaceMapDeviceCheckbox');
3937 + for (var i in elements) {
3938 + if (elements[i].checked) {
3939 + var node = getNodeFromId(elements[i].id.substring(0, elements[i].id.length - 8));
3940 + if (node) {
3941 + var feature = xxmap.markersSource.getFeatureById(i);
3942 + var v = ol.proj.transform(coords, 'EPSG:3857', 'EPSG:4326');
3943 + var vx = [ v[1], v[0] ]; // Flip the coordinates around, lat/long
3944 + if (feature) {
3945 + feature.getGeometry().setCoordinates(coords);
3946 + var activeInteraction = getActiveInteractions(feature);
3947 + if (activeInteraction) {
3948 + saveMarkerloc(feature);
3949 + } else { // If this feature is not saved after its location is changed, then send updated coords to server.
3950 + meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: vx }); // Send them to server to save changes
3951 + }
3952 + } else {
3953 + meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: vx }); // This Node is not yet added to maps.
3954 + }
3955 + }
3956 + }
3957 + }
3958 + }
3959 +
3960 + // Called when the user changes the search box
3961 + function onPlaceNodeInputChange() {
3962 + updatePlaceNodeTable(Q('selectnode-search').value.trim().toLowerCase());
3963 + }
3964 +
3965 + // Update the list of devices in the "place on map" table
3966 + function updatePlaceNodeTable(inputSearch) {
3967 + var elements = document.getElementsByName('PlaceMapDeviceCheckbox'), count = 0;
3968 + for (var i in nodes) {
3969 + var visible = ((nodes[i].namel.indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].rnamel != null && nodes[i].rnamel.indexOf(inputSearch) >= 0));
3970 + if (visible) { count++; }
3971 + QV(nodes[i]._id + '-rowid', visible);
3972 + }
3973 + QV('noNodesMapPlace', count == 0);
3974 + /*
3975 + console.log(selected);
3976 + for (var i in nodes) {
3977 + if ((nodes[i].name.toLowerCase().indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].rnamel != null && nodes[i].rnamel.toLowerCase().indexOf(inputSearch) >= 0)) {
3978 + console.log(selected.indexOf(nodes[i]._id));
3979 + 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':'') + ' />';
3980 + 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>';
3981 + }
3982 + }
3983 + if (x == '') { x = '<div style=text-align:center;width:100%>No devices found.</div>'; }
3984 + QH('placenode', '');
3985 + */
3986 + }
3987 +
3988 + // Called when a user clicks on a device to toggle selection for placement on map.
3989 + function selectNodeToPlace(e, id) {
3990 + // Toggle checkbox if needed
3991 + if (e.target.name != 'PlaceMapDeviceCheckbox') { var inputElement = Q(id + '-checkid'); inputElement.checked = !inputElement.checked; }
3992 +
3993 + // Check button state
3994 + var elements = document.getElementsByName('PlaceMapDeviceCheckbox'), checkcount = 0;
3995 + for (var i in elements) { if (elements[i].checked) checkcount++; }
3996 + QE('idx_dlgOkButton', checkcount > 0);
3997 + }
3998 +
3999 + // Add option for available meshes in mesh Dropdown
4000 + function addMeshOptions(addMeshid, meshName) {
4001 + /*
4002 + var meshOptions = Q('select-mesh');
4003 + if (addMeshid && meshName) {
4004 + var option = document.createElement('option');
4005 + option.value =addMeshid;
4006 + option.text = meshName;
4007 + meshOptions.add(option); // Add specific option
4008 + }
4009 + else {
4010 + for (var i in meshes) { // Add all options
4011 + var option = document.createElement('option');
4012 + option.value = i;
4013 + option.text = meshes[i].name;
4014 + meshOptions.add(option);
4015 + }
4016 + }
4017 + */
4018 + }
4019 +
4020 + // Remove/Modify options in Mesh dropdown (if modMeshname is defined then Modify else Remove)
4021 + function meshOptionRmvMod(delMeshid, modMeshname){
4022 + /*
4023 + var meshOptions = Q('select-mesh');
4024 + if (delMeshid) {
4025 + var index=-1;
4026 + for (var i = 1; i < meshOptions.options.length; i++) {
4027 + if (meshOptions[i].value === delMeshid) { index=i; }
4028 + }
4029 + if (index > 0) {
4030 + if (modMeshname) {
4031 + meshOptions[index].innerHTML=modMeshname; // If Mesh name is Modified
4032 + }
4033 + else { meshOptions.remove(index); }
4034 + }
4035 + }
4036 + */
4037 + }
4038 +
4039 + //Check if there is any mesh created
4040 + function meshExists() {
4041 + for (var i in meshes) { if (meshes[i]) { return true; } }
4042 + return false;
4043 + }
4044 +
4045 + // Reset Mesh dropdown option to 'All' when a current view mesh is deleted.
4046 + function setMeshView(emeshid) {
4047 + var selectMeshElement=Q('select-mesh');
4048 + var selectedIndex = selectMeshElement.selectedIndex;
4049 + if (selectMeshElement[selectedIndex].value == emeshid) { selectMeshElement[0].selected = true; onSelectMeshChange(); }
4050 + }
4051 +
4052 + // Clear all mesh options except 'All'
4053 + function clearMeshOptions() {
4054 + /*
4055 + var meshOptions=Q('select-mesh');
4056 + for(var i = meshOptions.options.length - 1 ; i > 0 ; i--) { meshOptions.remove(i); }
4057 + */
4058 + }
4059 +
4060 + // Make a http get call- Replace this with AJAX get if jquery is used
4061 + function getSearchLocation() {
4062 + try {
4063 + var searchdata = Q('mapSearchLocation').value.trim();
4064 + if (searchdata.length > 0) {
4065 + var xmlhttp = new XMLHttpRequest(); // Compatible with Chrome, Opera, Safari, IE7+, Firefox.
4066 + xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { formatSearchData(xmlhttp.responseText); } }
4067 + xmlhttp.open('GET', 'https://nominatim.openstreetmap.org/search?q=' + searchdata + '&format=json', true); // Get request
4068 + xmlhttp.send();
4069 + }
4070 + } catch (e) {}
4071 + }
4072 +
4073 + // Format data recieved from nominatim API and display it on content window
4074 + function formatSearchData(data) {
4075 + try {
4076 + QH('xmapSearchResults','');
4077 + var dataInfo = JSON.parse(data), count = 0, x = '<div class="xmapItem">';
4078 + for (var i = 0; i < dataInfo.length; i++) {
4079 + if (dataInfo[i].display_name && dataInfo[i].boundingbox[0] && dataInfo[i].boundingbox[1] && dataInfo[i].boundingbox[2] && dataInfo[i].boundingbox[3]) {
4080 + count++;
4081 + var itemclass = (i % 2 == 0)?'xmapItemSel1':'xmapItemSel1';
4082 + 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>';
4083 + }
4084 + }
4085 + x += '</div>';
4086 + if (count == 1) {
4087 + // If only one result is returned then zoom to that location
4088 + var extent = [ parseFloat(dataInfo[0].boundingbox[2]), parseFloat(dataInfo[0].boundingbox[0]), parseFloat(dataInfo[0].boundingbox[3]), parseFloat(dataInfo[0].boundingbox[1]) ];
4089 + zoomToExtent(extent);
4090 + } else {
4091 + if (count == 0) { x = '<div style=width:200px>' + "No location found." + '<div>'; }
4092 + QV('xmapSearchResultsDlg', true);
4093 + }
4094 + QH('xmapSearchResults', x);
4095 + }
4096 + catch (e) {}
4097 + }
4098 +
4099 + // Zoom into the bounding box
4100 + function mapGotoSelectedLocation(obj) {
4101 + var objchildren = obj.children;
4102 + var boundingBox = objchildren[1].innerHTML.split('!#!');
4103 + var extent = [parseFloat(boundingBox[2]), parseFloat(boundingBox[0]), parseFloat(boundingBox[3]), parseFloat(boundingBox[1])];
4104 + //Q('search-location').value = objchildren[0].innerHTML;
4105 + zoomToExtent(extent);
4106 + mapCloseSearchWindow();
4107 + }
4108 +
4109 + // Close the search window
4110 + function mapCloseSearchWindow() {
4111 + QH('xmapSearchResults', '');
4112 + QV('xmapSearchResultsDlg', false);
4113 + }
4114 +
4115 + // Zoom to specific cordinates
4116 + function zoomToLocation(coordinates, zoomVal) {
4117 + var view = xxmap.map.getView();
4118 + view.setCenter(coordinates);
4119 + view.setZoom(zoomVal);
4120 + }
4121 +
4122 + function zoomToFitExtent() {
4123 + var features = xxmap.markersSource.getFeatures();
4124 + if (features.length > 0) {
4125 + var extent = xxmap.markersSource.getExtent();
4126 + xxmap.map.getView().fit(extent, xxmap.map.getSize());
4127 + }
4128 + }
4129 +
4130 + function zoomToExtent(extent){
4131 + var boundingExtent = ol.proj.transformExtent(extent, ol.proj.get('EPSG:4326'), ol.proj.get('EPSG:3857'));
4132 + xxmap.map.getView().fit(boundingExtent, xxmap.map.getSize());
4133 + }
4134 +
4135 +
4136 + //
4137 + // MY DEVICE
4138 + //
4139 + function refreshDevice(nodeid) {
4140 + if (!currentNode || currentNode._id != nodeid) return;
4141 + gotoDevice(nodeid, xxcurrentView, true);
4142 + }
4143 +
4144 + function getNodeRights(nodeid) {
4145 + var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
4146 + return mesh.links[userinfo._id].rights;
4147 + }
4148 +
4149 + var currentNode;
4150 + var powerTimelineNode = null;
4151 + var powerTimelineReq = null;
4152 + var powerTimelineUpdate = null;
4153 + var powerTimeline = null;
4154 + function getCurrentNode() { return currentNode; };
4155 + function gotoDevice(nodeid, panel, refresh, event) {
4156 + // Remind the user to verify the email address
4157 + 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; }
4158 +
4159 + // Remind the user to add two factor authentication
4160 + 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; }
4161 +
4162 + if (event && (event.shiftKey == true)) {
4163 + // Open the device in a different tab
4164 + window.open(window.location.origin + '?node=' + nodeid.split('/')[2] + '&viewmode=10&hide=16', 'meshcentral:' + nodeid);
4165 + return;
4166 + }
4167 +
4168 + //disconnectAllKvmFunction();
4169 + var node = getNodeFromId(nodeid);
4170 + var mesh = meshes[node.meshid];
4171 + var meshrights = mesh.links[userinfo._id].rights;
4172 + if (!currentNode || currentNode._id != node._id || refresh == true) {
4173 + currentNode = node;
4174 +
4175 + // Add node name
4176 + var nname = EscapeHtml(node.name);
4177 + if (nname.length == 0) { nname = '<i>' + "None" + '</i>'; }
4178 + 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>'; }
4179 + nname += '<span style=color:#AAA;font-size:small> - ' + EscapeHtml(mesh.name) + '</span>';
4180 + QH('p10deviceName', nname);
4181 + QH('p11deviceName', nname);
4182 + QH('p12deviceName', nname);
4183 + QH('p13deviceName', nname);
4184 + QH('p14deviceName', nname);
4185 + QH('p15deviceName', "Console - " + nname);
4186 + QH('p16deviceName', nname);
4187 + QH('p17deviceName', nname);
4188 + QH('p19deviceName', nname);
4189 +
4190 + // Node attributes
4191 + var x = '<table style=width:100%>';
4192 +
4193 + // Attribute: Mesh
4194 + x += addDeviceAttribute('<span title=\"' + "The name of the device group this computer belong to." + '\">' + "Group" + '</span>', '<a href=# title=\"' + "Le nom du groupe de périphériques auquel cet ordinateur appartient" + '\" onclick=gotoMesh("' + node.meshid + '") style=cursor:pointer>' + EscapeHtml(meshes[node.meshid].name) + '</a>');
4195 +
4196 + // Attribute: Name
4197 + 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>'); }
4198 +
4199 + // Attribute: Host
4200 + if ((features & 1) == 0) { // If not WAN-only, local hostname is in use
4201 + if ((meshrights & 4) != 0) {
4202 + if (node.host) {
4203 + x += addDeviceAttribute("Hostname", '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer>' + EscapeHtml(node.host) + '</span>');
4204 + } else {
4205 + x += addDeviceAttribute("Hostname", '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer><i>' + "None" + '</i></span>');
4206 + }
4207 + } else {
4208 + x += addDeviceAttribute("Hostname", EscapeHtml(node.host));
4209 + }
4210 + }
4211 +
4212 + // Attribute: Description
4213 + var description = node.desc?EscapeHtml(node.desc):('<i>' + "None" + '</i>');
4214 + if ((meshrights & 4) != 0) {
4215 + x += addDeviceAttribute("Description", '<span onclick=showEditNodeValueDialog(2) style=cursor:pointer>' + description + ' <img class=hoverButton src="images/link5.png" /></span>');
4216 + } else {
4217 + x += addDeviceAttribute("Description", description);
4218 + }
4219 +
4220 + // Attribute: Mesh Agent
4221 + var agentsStr = ["Inconnue", "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", "Inconnue", "Inconnue", "FreeBSD x86-64"];
4222 + if ((node.agent != null) && (node.agent.id != null) && (node.agent.ver != null)) {
4223 + var str = '';
4224 + if (node.agent.id <= agentsStr.length) { str = agentsStr[node.agent.id]; } else { str = agentsStr[0]; }
4225 + if (node.agent.ver != 0) { str += ' v' + node.agent.ver; }
4226 + x += addDeviceAttribute("Mesh Agent", str);
4227 + }
4228 +
4229 + // Attribute: Intel AMT
4230 + if (node.intelamt != null) {
4231 + var str = '';
4232 + var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activé") };
4233 + if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>' + "Etat inconnu" + '</i>, v' + node.intelamt.ver; } else
4234 +
4235 + if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '<i>' + "Activé" + '</i>'; }
4236 + else if ((node.intelamt.ver == null) || (node.intelamt.state == null)) { str += '<i>' + "Version et état inconnus" + '</i>'; }
4237 + else {
4238 + str += provisioningStates[node.intelamt.state];
4239 + 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>'; } }
4240 + str += (', v' + node.intelamt.ver);
4241 + }
4242 +
4243 + if (node.intelamt.tls == 1) { str += ', <span title=\"' + "Intel AMT is setup with TLS network security" + '\">' + "TLS" + '</span>'; }
4244 + if (node.intelamt.state == 2) {
4245 + if (node.intelamt.user == null || node.intelamt.user == '') {
4246 + if ((meshrights & 4) != 0) {
4247 + str += ', <i style=color:#FF0000;cursor:pointer title=\"' + "Edit Intel&reg; AMT credentials" + '\" onclick=editDeviceAmtSettings("' + node._id + '")>' + "No Credentials" + '</i>';
4248 + } else {
4249 + str += ', <i style=color:#FF0000>' + "No Credentials" + '</i>';
4250 + }
4251 + }
4252 + str += ' ';
4253 + if ((meshrights & 4) != 0) {
4254 + str += '<img src=images/link4.png height=10 width=10 title=\"' + "Edit Intel&reg; AMT credentials" + '\" style=cursor:pointer onclick=editDeviceAmtSettings("' + node._id + '")>';
4255 + }
4256 + }
4257 +
4258 + var meName = '<span title=\"Intel&reg; Manageability Engine\">' + "Intel&reg; ME" + '<span>';
4259 + if (typeof node.intelamt.sku == 'number') {
4260 + if ((node.intelamt.sku & 8) != 0) { meName = '<span title=\"' + "Intel&reg; Active Management Technology" + '\">' + "Intel&reg; AMT" + '<span>'; }
4261 + else if ((node.intelamt.sku & 16) != 0) { meName = '<span title=\"' + "Intel&reg; Standard Manageability" + '\">' + "Intel&reg; SM" + '<span>'; }
4262 + }
4263 + x += addDeviceAttribute(meName, str);
4264 + }
4265 +
4266 + if (mesh.mtype == 2) {
4267 + // Attribute: Mesh Agent Tag
4268 + if ((node.agent != null) && (node.agent.tag != null)) {
4269 + var tag = EscapeHtml(node.agent.tag);
4270 + if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
4271 + x += addDeviceAttribute("Agent Tag", tag);
4272 + }
4273 + } else {
4274 + // Attribute: Intel AMT Tag
4275 + if ((node.intelamt != null) && (node.intelamt.tag != null)) {
4276 + var tag = EscapeHtml(node.intelamt.tag);
4277 + if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
4278 + x += addDeviceAttribute("Intel&reg; AMT Tag", tag);
4279 + }
4280 + }
4281 +
4282 + // Attribute: Intel AMT
4283 + //if (node.intelamt && node.intelamt.user) { x += addDeviceAttribute('Intel&reg; AMT', node.intelamt.user); }
4284 +
4285 + // Operating system description
4286 + if (node.osdesc) { x += addDeviceAttribute("Operating System", node.osdesc); }
4287 +
4288 + // Antivirus
4289 + if (node.av && node.av.length > 0) {
4290 + var y = [];
4291 + for (var i in node.av) {
4292 + if (node.av[i].product) {
4293 + var avx = EscapeHtml(node.av[i].product);
4294 + if (node.av[i].enabled !== true) { avx += ' - <span style=color:red>' + "Disabled" + '</span>'; }
4295 + if (node.av[i].updated !== true) { avx += ' - <span style=color:red>' + "Out of date" + '</span>'; }
4296 + if ((node.av[i].enabled == true) && (node.av[i].updated == true)) { avx += ' - <span style=color:green>' + "OK" + '</span>'; }
4297 + y.push(avx);
4298 + }
4299 + }
4300 + x += addDeviceAttribute("Antivirus", y.join('<br />'));
4301 + }
4302 +
4303 + // Active Users
4304 + if (node.users && node.conn && (node.users.length > 0) && (node.conn & 1)) { x += addDeviceAttribute(format("Active User{0}", ((node.users.length > 1)?'s':'')), node.users.join(', ')); }
4305 +
4306 + // Attribute: Connectivity (Only show this if more than just the agent is connected).
4307 + var connectivity = node.conn;
4308 + if (connectivity && connectivity > 1) {
4309 + var cstate = [];
4310 + if ((node.conn & 1) != 0) cstate.push('<span title=\"' + "Mesh agent is connected and ready for use." + '\">' + "Mesh Agent" + '</span>');
4311 + if ((node.conn & 2) != 0) cstate.push('<span title=\"' + "Intel&reg; AMT CIRA is connected and ready for use." + '\">' + "Intel&reg; AMT CIRA" + '</span>');
4312 + else if ((node.conn & 4) != 0) cstate.push('<span title=\"' + "Intel&reg; AMT is routable and ready for use." + '\">' + "Intel&reg; AMT" + '</span>');
4313 + if ((node.conn & 8) != 0) cstate.push('<span title=\"' + "Mesh agent is reachable using another agent as relay." + '\">' + "Mesh Relay" + '</span>');
4314 + if ((node.conn & 16) != 0) { cstate.push('<span title=\"' + "MQTT connection to the device is active." + '\">' + "MQTT" + '</span>'); }
4315 + x += addDeviceAttribute("Connectivity", cstate.join(', '));
4316 + }
4317 +
4318 + // Node grouping tags
4319 + var groupingTags = '<i>' + "None" + '</i>';
4320 + if (node.tags != null) { groupingTags = ''; for (var i in node.tags) { groupingTags += '<span class="tagSpan">' + node.tags[i] + '</span>'; } }
4321 + if ((meshrights & 4) != 0) {
4322 + x += addDeviceAttribute('Tags', '<span onclick=showEditNodeValueDialog(3) style=cursor:pointer>' + groupingTags + ' <img class=hoverButton src="images/link5.png" /></span>');
4323 + } else {
4324 + x += addDeviceAttribute('Tags', groupingTags);
4325 + }
4326 +
4327 + x += '</table><br />';
4328 + // Show action button, only show if we have permissions 4, 8, 64
4329 + if ((meshrights & 76) != 0) { x += '<input type=button value=\"' + "Actions" + '\" title=\"' + "Perform power actions on the device" + '\" onclick=deviceActionFunction() />'; }
4330 + x += '<input type=button value=\"' + "Notes" + '\" title=\"' + "View notes about this device" + '\" onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
4331 + x += '<input type=button value=\"' + "Log Event" + '\" title=\"' + "Écrire un événement pour ce périphérique" + '\" onclick=writeDeviceEvent("' + encodeURIComponent(node._id) + '") />';
4332 + //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() />'; }
4333 + QH('p10html', x);
4334 +
4335 + // Show node last 7 days timeline
4336 + masterUpdate(256);
4337 +
4338 + // Show bottom buttons
4339 + x = '<div class="p10html3right">';
4340 + if ((meshrights & 4) != 0) {
4341 + // TODO: Show change group only if there is another mesh of the same type.
4342 + x += '&nbsp;<a href=# onclick=p10showChangeGroupDialog(["' + node._id + '"]) title=\"' + "Move this device to a different device group" + '\">' + "Change Group" + '</a>';
4343 + x += '&nbsp;<a href=# onclick=p10showDeleteNodeDialog("' + node._id + '") title=\"' + "Remove this device" + '\">' + "Delete Device" + '</a>';
4344 + }
4345 + x += '</div><div class="p10html3left">';
4346 + if (mesh.mtype == 2) x += '<a href=# onclick=p10showNodeNetInfoDialog("' + node._id + '") title=\"' + "Show device network interface information" + '\">' + "Interfaces" + '</a>&nbsp;';
4347 + if (xxmap != null) x += '<a href=# onclick=p10showNodeLocationDialog("' + node._id + '") title=\"' + "Show device locations information" + '\">' + "Location" + '</a>&nbsp;';
4348 + 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>&nbsp;';
4349 +
4350 + // RDP link, show this link only of the remote machine is Windows.
4351 + if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0)) {
4352 + 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>&nbsp;'; }
4353 + if (node.agent.id > 4) {
4354 + x += '<a href=# onclick=p10clickOnce("' + node._id + '","PSSH",22) title=\"' + "Requires Microsoft ClickOnce support in your browser." + '\">' + "Putty" + '</a>&nbsp;';
4355 + x += '<a href=# onclick=p10clickOnce("' + node._id + '","WSCP",22) title=\"' + "Requires Microsoft ClickOnce support in your browser." + '\">' + "WinSCP" + '</a>&nbsp;';
4356 + }
4357 + }
4358 +
4359 + // MQTT options
4360 + if ((meshrights == 0xFFFFFFFF) && (features & 0x00400000)) { x += '<a href=# onclick=p10showMqttLoginDialog("' + node._id + '") title=\"' + "Get MQTT login credentials for this device." + '\">' + "MQTT Login" + '</a>&nbsp;'; }
4361 + x += '</div><br>'
4362 +
4363 + QH('p10html3', x);
4364 +
4365 + // Set the node power state
4366 + var powerstate = PowerStateStr(node.state);
4367 + //if (node.state == 0) { powerstate = 'Unknown State'; }
4368 + if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title=\"' + "Agent connected" + '\">' + "Agent connected" + '</span>'; }
4369 + if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title=\"' + "Intel&reg; AMT connected" + '\">' + "Intel&reg; AMT connected" + '</span>'; }
4370 + else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title=\"' + "Intel&reg; AMT detected" + '\">' + "Intel&reg; AMT detected" + '</span>'; }
4371 + if ((connectivity & 16) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title=\"' + "MQTT connected" + '\">' + "MQTT channel connected" + '</span>'; }
4372 + if ((powerstate == '') && node.lastconnect) { powerstate = '<span style=font-size:12px>' + "Last seen:" + '<br />' + printDateTime(new Date(node.lastconnect)) + '</span>'; }
4373 + QH('MainComputerState', powerstate);
4374 +
4375 + // Set the node icon
4376 + Q('MainComputerImage').setAttribute('src', 'images/icons256-' + node.icon + '-1.png');
4377 + Q('MainComputerImage').className = ((!node.conn) || (node.conn == 0)?'gray':'');
4378 +
4379 + // Check if we have terminal and file access
4380 + var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0));
4381 + var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0));
4382 + var amtAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 2048) == 0));
4383 +
4384 + // Setup/Refresh the desktop tab
4385 + if (terminalAccess) { setupTerminal(); }
4386 + if (fileAccess) { setupFiles(); }
4387 + var consoleRights = ((meshrights & 16) != 0);
4388 + if (consoleRights) { setupConsole(); } else { if (panel == 15) { panel = 10; } }
4389 +
4390 + // Show or hide the tabs
4391 + // mesh.mtype: 1 = Intel AMT only, 2 = Mesh Agent
4392 + // node.agent.caps (bitmask): 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console
4393 + QV('MainDevDesktop', (((mesh.mtype == 1) && ((typeof node.intelamt.sku !== 'number') || ((node.intelamt.sku & 8) != 0)))
4394 + || ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2)))))
4395 + && ((meshrights & 8) || (meshrights & 256))
4396 + );
4397 + 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);
4398 + QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess);
4399 + QV('MainDevAmt', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8) && amtAccess);
4400 + QV('MainDevConsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
4401 + QV('MainDevPlugins', pluginHandler != null);
4402 + QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0));
4403 + QH('p15coreName', ((node.agent != null) && (node.agent.core != null))?node.agent.core:'');
4404 +
4405 + // Setup/Refresh Intel AMT tab
4406 + var amtFrameNode = Q('p14iframe').contentWindow.getCurrentMeshNode();
4407 + if ((amtFrameNode != null) && (amtFrameNode._id != currentNode._id)) { Q('p14iframe').contentWindow.disconnect(); }
4408 + var online = ((node.conn & 6) != 0)?true:false; // If CIRA (2) or AMT (4) connected, enable Commander
4409 + Q('p14iframe').contentWindow.setConnectionState(online);
4410 + Q('p14iframe').contentWindow.setFrameHeight('650px');
4411 + Q('p14iframe').contentWindow.setAuthCallback(updateAmtCredentials);
4412 +
4413 + // Display "action" button on desktop/terminal/files
4414 + QV('deskActionsBtn', (meshrights & 72) != 0); // 72 = Wake-up + Remote Control permissions
4415 + QV('termActionsBtn', (meshrights & 72) != 0);
4416 + QV('filesActionsBtn', (meshrights & 72) != 0);
4417 +
4418 + // Request the power timeline
4419 + if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) {
4420 + QH('p10html2', '');
4421 + powerTimelineReq = currentNode._id;
4422 + meshserver.send({ action: 'powertimeline', nodeid: currentNode._id });
4423 + meshserver.send({ action: 'lastconnect', nodeid: currentNode._id });
4424 + meshserver.send({ action: 'getsysinfo', nodeid: currentNode._id });
4425 + QH('p17info', '');
4426 + }
4427 +
4428 + // Reset the desktop tools
4429 + QV('DeskTools', false);
4430 + showDeskToolsProcesses();
4431 +
4432 + // Ask for device events
4433 + refreshDeviceEvents();
4434 +
4435 + // Update the web page title
4436 + if ((currentNode) && (xxcurrentView >= 10) && (xxcurrentView < 20)) {
4437 + document.title = decodeURIComponent('{{{extitle}}}') + ' - ' + currentNode.name + ' - ' + mesh.name;
4438 + } else {
4439 + document.title = decodeURIComponent('{{{extitle}}}');
4440 + }
4441 +
4442 + // Clear user consent status if present
4443 + p11clearConsoleMsg();
4444 + p12clearConsoleMsg();
4445 + p13clearConsoleMsg();
4446 +
4447 + // Device refresh plugin handler
4448 + if (pluginHandler != null) { pluginHandler.onDeviceRefeshEnd(nodeid, panel, refresh, event); }
4449 + }
4450 + setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
4451 + if (!panel) panel = 10;
4452 + go(panel);
4453 + }
4454 +
4455 + function writeDeviceEvent(nodeid) {
4456 + if (xxdialogMode) return;
4457 + setDialogMode(2, "Ajouter un événement", 3, writeDeviceEventEx, '<textarea id=d2devEvent style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea><span style=font-size:10px>' + "This will add an entry to this device\'s event log." + '<span>', nodeid);
4458 + }
4459 +
4460 + function writeDeviceEventEx(buttons, tag) { meshserver.send({ action: 'setDeviceEvent', nodeid: decodeURIComponent(tag), msg: encodeURIComponent(Q('d2devEvent').value) }); }
4461 +
4462 + function showNotes(readonly, noteid) {
4463 + if (xxdialogMode) return;
4464 + 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);
4465 + meshserver.send({ action: 'getNotes', id: decodeURIComponent(noteid) });
4466 + }
4467 +
4468 + function showNotesEx(buttons, tag) { meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponent(Q('d2devNotes').value) }); }
4469 +
4470 + function deviceChat() {
4471 + if (xxdialogMode) return;
4472 + var url = '/messenger?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name;
4473 + if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
4474 + window.open(url, 'meshmessenger:' + currentNode._id);
4475 + meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
4476 + }
4477 +
4478 + function deviceUrlFunction() {
4479 + if (xxdialogMode) return;
4480 + setDialogMode(2, "Open Page on Device", 3, deviceUrlFunctionEx, '<input id=d2devurl placeholder="http://server.com" style=width:100%;overflow-y:scroll></input>');
4481 + Q('d2devurl').focus();
4482 + }
4483 +
4484 + function deviceUrlFunctionEx() {
4485 + meshserver.send({ action: 'msg', type: 'openUrl', nodeid: currentNode._id, url: Q('d2devurl').value });
4486 + }
4487 +
4488 + function deviceToastFunction() {
4489 + if (xxdialogMode) return;
4490 + setDialogMode(2, "Device Notification", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
4491 + Q('d2devToast').focus();
4492 + }
4493 +
4494 + function deviceToastFunctionEx() {
4495 + meshserver.send({ action: 'toast', nodeids: [ currentNode._id ], title: 'MeshCentral', msg: Q('d2devToast').value });
4496 + }
4497 +
4498 + function deviceActionFunction() {
4499 + if (xxdialogMode) return;
4500 + var meshrights = meshes[currentNode.meshid].links[userinfo._id].rights;
4501 + var x = "Select an operation to perform on this device." + '<br /><br />';
4502 + var y = '<select id=d2deviceop style=float:right;width:250px>';
4503 + if ((meshrights & 64) != 0) { y += '<option value=100>' + "Wake-up" + '</option>'; } // Wake-up permission
4504 + if ((meshrights & 8) != 0) { y += '<option value=4>' + "Sleep" + '</option><option value=3>' + "Reset" + '</option><option value=2>' + "Power off" + '</option>'; } // Remote control permission
4505 + if ((currentNode.conn & 16) != 0) { y += '<option value=103>' + "Send MQTT Message" + '</option>'; }
4506 + y += '</select>';
4507 + x += addHtmlValue("Operation", y);
4508 + setDialogMode(2, "Device Action", 3, deviceActionFunctionEx, x);
4509 + }
4510 +
4511 + function deviceActionFunctionEx() {
4512 + var op = Q('d2deviceop').value;
4513 + if (op == 100) {
4514 + // Device wake
4515 + meshserver.send({ action: 'wakedevices', nodeids: [currentNode._id] });
4516 + } else if (op == 103) {
4517 + // Send MQTT Message
4518 + p10showSendMqttMsgDialog([currentNode._id]);
4519 + } else {
4520 + // Power operation
4521 + meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: parseInt(op) });
4522 + }
4523 + }
4524 +
4525 + // Called when MeshCommander needs new credentials or updated credentials.
4526 + function updateAmtCredentials(forceDialog) {
4527 + var node = getNodeFromId(currentNode._id);
4528 + if ((forceDialog == true) || (node.intelamt.user == null) || (node.intelamt.user == '')) {
4529 + editDeviceAmtSettings(currentNode._id, updateAmtCredentialsEx);
4530 + } else {
4531 + Q('p14iframe').contentWindow.connectButtonfunctionEx();
4532 + }
4533 + }
4534 +
4535 + function updateAmtCredentialsEx(button, tag) {
4536 + Q('p14iframe').contentWindow.connectButtonfunctionEx();
4537 + }
4538 +
4539 + // Look to see if we need to update the device timeline
4540 + function updateDeviceTimeline() {
4541 + if ((meshserver.State != 2) || (powerTimelineNode == null) || (powerTimelineUpdate == null) || (currentNode == null)) return;
4542 + if ((powerTimelineNode == powerTimelineReq) && (currentNode._id == powerTimelineNode) && (powerTimelineUpdate < Date.now())) {
4543 + powerTimelineUpdate = null;
4544 + meshserver.send({ action: 'powertimeline', nodeid: currentNode._id });
4545 + meshserver.send({ action: 'lastconnect', nodeid: currentNode._id });
4546 + }
4547 + }
4548 +
4549 + // Draw device power bars. The bars are 766px wide.
4550 + function drawDeviceTimeline() {
4551 + if ((currentNode == null) || (xxcurrentView < 10) || (xxcurrentView > 19)) return;
4552 + var timeline = null, now = Date.now();
4553 + if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
4554 +
4555 + // Calculate when the timeline starts
4556 + var d = new Date();
4557 + d.setHours(0, 0, 0, 0);
4558 + d = new Date(d.getTime() - (1000 * 60 * 60 * 24 * 6));
4559 + var timelineStart = d.getTime();
4560 +
4561 + // De-compact the timeline
4562 + var timeline2 = [];
4563 + if (timeline != null && timeline.length > 1) {
4564 + timeline2.push([ 0, timeline[1], timeline[0] ]); // Start, End, Power
4565 + var ct = timeline[1];
4566 + for (var i = 2; i < timeline.length; i += 2) {
4567 + var power = timeline[i], dt = now;
4568 + if (timeline.length > (i + 1)) { dt = timeline[i + 1]; }
4569 + timeline2.push([ ct, ct + dt, power ]); // Start, End, Power
4570 + ct = ct + dt;
4571 + }
4572 + }
4573 +
4574 + // Draw the timeline
4575 + var x = '', count = 1, date = new Date();
4576 + var totalWidth = Q('masthead').offsetWidth - (160 + 9 + 9 + 14); // Compute the total width of the power bar
4577 + date.setHours(0, 0, 0, 0);
4578 + for (var i = 0; i < 7; i++) {
4579 + var datavalue = '', start = date.getTime(), end = start + (1000 * 60 * 60 * 24);
4580 + for (var j in timeline2) {
4581 + var block = timeline2[j];
4582 + if (isTimeBlockInside(start, end, block[0], block[1]) == true) {
4583 + var ts = Math.max(start, block[0]);
4584 + var te = Math.min(Math.min(end, block[1]), now);
4585 + var width = Math.round(((te - ts) * totalWidth) / 86400000);
4586 + if (width > 0) {
4587 + var title = format('{0} from {1} to {2}.', powerStateStrings2[block[2]], printTime(new Date(ts)), printTime(new Date(te)));
4588 + datavalue += '<div class="pwState ' + powerColor(block[2]) + '" title="' + title + '" style="width:' + width + 'px;"></div>';
4589 + }
4590 + }
4591 + }
4592 + x += '<tr class=' + (((count % 2) == 0)?'altBack':'') + '><td><div>&nbsp;' + printDate(date) + '<div></div></div></td><td><div>' + datavalue + '</div></td></tr>';
4593 + ++count;
4594 + date = new Date(date.getTime() - (1000 * 60 * 60 * 24)); // Substract one day
4595 + }
4596 + 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>');
4597 + }
4598 +
4599 + // Return a color for the given power state
4600 + function powerColor(x) { if (x < powerColorTable.length) { return powerColorTable[x]; } return 'pwsYellow'; }
4601 +
4602 + // Return true if the time block is visible within the start/end period
4603 + function isTimeBlockInside(start, end, blockStart, blockEnd) {
4604 + if ((blockStart < start) && (blockEnd > end)) return true; // Block is wider than timespan
4605 + if ((blockStart > start) && (blockStart < end)) return true;
4606 + if ((blockEnd > start) && (blockEnd < end)) return true;
4607 + return false;
4608 + }
4609 +
4610 + function addDeviceAttribute(name, value) { return '<tr><td class=style7>' + name + '</td><td class=style9>' + value + '</td></tr>'; }
4611 +
4612 + function editDeviceAmtSettings(nodeid, func, arg) {
4613 + if (xxdialogMode) return;
4614 + var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
4615 + if ((meshrights & 4) == 0) return;
4616 + x += addHtmlValue("Nom d'utilisateur", '<input id=dp10username style=width:230px maxlength=32 autocomplete=nope placeholder="admin" onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
4617 + x += addHtmlValue("Password", '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
4618 + x += addHtmlValue("Security", '<select id=dp10tls style=width:236px><option value=0>' + "No TLS security" + '</option><option value=1>' + "Sécurité TLS requise" + '</option></select>');
4619 + if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
4620 + setDialogMode(2, "Edit Intel&reg; AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func, arg: arg });
4621 + if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
4622 + Q('dp10tls').value = node.intelamt.tls;
4623 + validateDeviceAmtSettings();
4624 + }
4625 +
4626 + function validateDeviceAmtSettings() {
4627 + QE('idx_dlgOkButton', passwordcheck(Q('dp10password').value));
4628 + }
4629 +
4630 + function editDeviceAmtSettingsEx(button, tag) {
4631 + if (button == 2) {
4632 + // Delete button pressed, remove credentials
4633 + meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: '', pass: '' } });
4634 + } else {
4635 + // Change Intel AMT credentials
4636 + var amtuser = Q('dp10username').value;
4637 + if (amtuser == '') amtuser = 'admin';
4638 + var amtpass = Q('dp10password').value;
4639 + if (amtpass == '') amtuser = '';
4640 + meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
4641 + tag.node.intelamt.user = amtuser;
4642 + tag.node.intelamt.tls = Q('dp10tls').value;
4643 + if (tag.func) { setTimeout(function () { tag.func(null, tag.arg); }, 300); }
4644 + }
4645 + }
4646 +
4647 + function p10showSendMqttMsgDialog(nodeids) {
4648 + if (xxdialogMode) return false;
4649 + var x = addHtmlValue("Topic", '<input id=dp2topic style=width:230px maxlength=64 onchange=p10validateSendMqttMsgDialog() onkeyup=p10validateSendMqttMsgDialog(event,1) />');
4650 + x += addHtmlValue("Message", '<div style=width:230px;margin:0;padding:0><textarea id=dp2msg maxlength=4096 style=width:100%;height:150px;resize:none onchange=p10validateSendMqttMsgDialog() onkeyup=p10validateSendMqttMsgDialog(event,1)></textarea></div>');
4651 + setDialogMode(2, "Send MQTT message", 3, p10showSendMqttMsgDialogEx, x, nodeids);
4652 + p10validateSendMqttMsgDialog();
4653 + Q('dp2topic').focus();
4654 + return false;
4655 + }
4656 +
4657 + function p10validateSendMqttMsgDialog() {
4658 + QE('idx_dlgOkButton', (Q('dp2topic').value.length > 0) && (Q('dp2msg').value.length > 0));
4659 + }
4660 +
4661 + function p10showSendMqttMsgDialogEx(b, nodeids) {
4662 + meshserver.send({ action: 'sendmqttmsg', nodeids: nodeids, topic: Q('dp2topic').value, msg: Q('dp2msg').value });
4663 + }
4664 +
4665 + function p10showChangeGroupDialog(nodeids) {
4666 + if (xxdialogMode) return false;
4667 + var targetMeshId = null;
4668 + if (nodeids.length == 1) { try { targetMeshId = meshes[getNodeFromId(nodeids[0])]._id; } catch (ex) { } }
4669 +
4670 + // List all available alternative groups
4671 + var y = '<select id=p10newGroup style=width:236px>', count = 0;
4672 + for (var i in meshes) {
4673 + var meshrights = meshes[i].links[userinfo._id].rights;
4674 + if ((meshes[i]._id != targetMeshId) && (meshrights & 4)) { count++; y += '<option value=\'' + meshes[i]._id + '\'>' + meshes[i].name + '</option>'; }
4675 + }
4676 + y += '</select>';
4677 +
4678 + if (count > 0) {
4679 + var x = (nodeids.length == 1) ? ("Select a new group for this device" + '<br /><br />') : ("Select a new group for selected devices" + '<br /><br />');
4680 + x += addHtmlValue("New Device Group", y);
4681 + setDialogMode(2, "Change Group", 3, p10showChangeGroupDialogEx, x, nodeids);
4682 + } else {
4683 + setDialogMode(2, "Change Group", 1, null, "No other device group of same type exists.");
4684 + }
4685 + return false;
4686 + }
4687 +
4688 + function p10showChangeGroupDialogEx(b, nodeids) {
4689 + meshserver.send({ action: 'changeDeviceMesh', nodeids: nodeids, meshid: Q('p10newGroup').value });
4690 + }
4691 +
4692 + function p10showDeleteNodeDialog(nodeid) {
4693 + if (xxdialogMode) return false;
4694 + var x = format("Êtes-vous sûr de vouloir supprimer le noeud {0}?", EscapeHtml(currentNode.name)) + '<br /><br /><label><input id=p10check type=checkbox onchange=p10validateDeleteNodeDialog() />' + "Confirm" + '</label>';
4695 + setDialogMode(2, "Delete Node", 3, p10showDeleteNodeDialogEx, x, nodeid);
4696 + p10validateDeleteNodeDialog();
4697 + return false;
4698 + }
4699 +
4700 + function p10validateDeleteNodeDialog() {
4701 + QE('idx_dlgOkButton', Q('p10check').checked);
4702 + }
4703 +
4704 + function p10showDeleteNodeDialogEx(buttons, nodeid) {
4705 + meshserver.send({ action: 'removedevices', nodeids: [ nodeid ] });
4706 + }
4707 +
4708 + function p10clickOnce(nodeid, protocol, port) {
4709 + meshserver.send({ action: 'getcookie', nodeid: nodeid, tcpport: port, tag: 'clickonce', protocol: protocol });
4710 + return false;
4711 + }
4712 +
4713 + // Show current location
4714 + var d2map = null;
4715 + function p10showNodeLocationDialog() {
4716 + if ((xxdialogMode != null) && (xxdialogTag == '@xxmap')) { setDialogMode(0); } else { if (xxdialogMode) return false; }
4717 + var markers = [], types = ['iploc', 'wifiloc', 'gpsloc', 'userloc'], boundingBox = null;
4718 +
4719 + for (var loctype in types) {
4720 + if (currentNode[types[loctype]] != null) {
4721 + var loc = currentNode[types[loctype]].split(','), lat = parseFloat(loc[0]), lon = parseFloat(loc[1]);
4722 + if ((lat < 90) && (lat > -90) && (lon < 180) && (lon > -180)) { // Check valid lat/lon
4723 + var deviceMark = new ol.Feature({ geometry: new ol.geom.Point(ol.proj.fromLonLat([lon, lat])) });
4724 + deviceMark.setStyle(markerStyle(currentNode, parseInt(loctype) + 1));
4725 + markers.push(deviceMark);
4726 +
4727 + 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; } }
4728 + }
4729 + }
4730 + }
4731 +
4732 + // Setup the device mark layer
4733 + var vectorSource = new ol.source.Vector({ features: markers });
4734 + var vectorLayer = new ol.layer.Vector({ source: vectorSource });
4735 +
4736 + //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>';
4737 + var x = '<div id=d2map style=width:100%;height:300px></div>';
4738 + setDialogMode(2, "Device Location", 1, null, x, '@xxmap');
4739 +
4740 + var clng = 0, clat = 0, zoom = 8;
4741 + if (boundingBox != null) {
4742 + var clat = (boundingBox[0] + boundingBox[2]) / 2;
4743 + var clng = (boundingBox[1] + boundingBox[3]) / 2;
4744 + var cscale = Math.max(Math.abs(boundingBox[0] - boundingBox[2]), Math.abs(boundingBox[1] - boundingBox[3]));
4745 + var i = 360, zoom = -2;
4746 + while (i > cscale) { zoom++; i = i / 2; }
4747 + }
4748 +
4749 + if (markers.length == 1) { zoom = 8; }
4750 +
4751 + // Setup the map
4752 + d2map = new ol.Map({
4753 + target: 'd2map',
4754 + interactions: ol.interaction.defaults({dragPan:false, mouseWheelZoom:false}),
4755 + layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer ],
4756 + view: new ol.View({ center: ol.proj.fromLonLat([clng, clat]), zoom: zoom })
4757 + });
4758 + return false;
4759 + }
4760 +
4761 + // Show network interfaces
4762 + function p10showNodeNetInfoDialog() {
4763 + if (xxdialogMode) return false;
4764 + setDialogMode(2, "Network Interfaces", 1, null, '<div id=d2netinfo>' + "Loading..." + '</div>', 'if' + currentNode._id );
4765 + meshserver.send({ action: 'getnetworkinfo', nodeid: currentNode._id });
4766 + return false;
4767 + }
4768 +
4769 + // Show MeshCentral Router dialog
4770 + function p10showMeshRouterDialog() {
4771 + if (xxdialogMode) return;
4772 + 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 />';
4773 + x += addHtmlValue('Win32 Executable', '<a style=cursor:pointer download href="meshagents?meshaction=winrouter" onclick="setDialogMode(0)">MeshCentralRouter.exe</a>');
4774 + setDialogMode(2, "MeshCentral Router", 1, null, x, 'fileDownload');
4775 + }
4776 +
4777 + // Request MQTT login credentials
4778 + function p10showMqttLoginDialog(nodeid) { meshserver.send({ action: 'getmqttlogin', nodeid: nodeid }); }
4779 +
4780 + // Show MeshCmd dialog
4781 + function p10showMeshCmdDialog(mode, nodeid) {
4782 + if (xxdialogMode) return;
4783 + var y = '<select id=aginsSelect onclick=meshCmdOsClick() style=width:236px>';
4784 + y += '<option value=3>' + "Windows (32bit)" + '</option>';
4785 + y += '<option value=4>' + "Windows (64bit)" + '</option>';
4786 + y += '<option value=5>' + "Linux x86 (32bit)" + '</option>';
4787 + y += '<option value=6>' + "Linux x86 (64bit)" + '</option>';
4788 + y += '<option value=16>' + "MacOS (64bit)" + '</option>';
4789 + y += '<option value=25>' + "Linux ARM, Raspberry Pi (32bit)" + '</option>';
4790 + y += '</select>';
4791 +
4792 + var x = '';
4793 + 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 />'; }
4794 + 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 />'; }
4795 + x += addHtmlValue('Operating System', y);
4796 + x += addHtmlValue('MeshCmd', '<a id=meshcmddownloadid href="meshagents?meshcmd=3" download></a>');
4797 + if (mode == 0) { x += addHtmlValue('Action File', '<a href="meshagents?meshaction=generic" download>MeshAction (.txt)</a>'); }
4798 + if (mode == 1) { x += addHtmlValue('Action File', '<a href="meshagents?meshaction=route&nodeid=' + nodeid + '" download>MeshAction (.txt)</a>'); }
4799 + x += '</div>';
4800 + setDialogMode(2, [ "Download MeshCmd", "Network Router" ][mode], 9, null, x, 'fileDownload');
4801 + meshCmdOsClick();
4802 + }
4803 +
4804 + function meshCmdOsClick() {
4805 + var os = Q('aginsSelect').value, osn = '', osurl = '';
4806 + //Q('meshcmddownloadid').href = 'meshagents?meshcmd=' + os;
4807 + if (os == 3) { osn = 'MeshCmd (Win32 executable)'; }
4808 + if (os == 4) { osn = 'MeshCmd (Win64 executable)'; }
4809 + if (os == 5) { osn = 'MeshCmd (Linux x86, 32bit)'; }
4810 + if (os == 6) { osn = 'MeshCmd (Linux x86, 64bit)'; }
4811 + if (os == 16) { osn = 'MeshCmd (MacOS, 64bit)'; }
4812 + if (os == 25) { osn = 'MeshCmd (Linux ARM, 32bit)'; }
4813 + QH('meshcmddownloadid', osn);
4814 + Q('meshcmddownloadid').setAttribute('href', 'meshagents?meshcmd=' + os);
4815 + }
4816 +
4817 + function p10showiconselector() {
4818 + if (xxdialogMode) return;
4819 + var mesh = meshes[currentNode.meshid];
4820 + var meshrights = mesh.links[userinfo._id].rights;
4821 + if ((meshrights & 4) == 0) return;
4822 +
4823 + var x = '<br><div style=display:inline-block;width:40px></div>';
4824 + x += '<div tabindex=0 style=display:inline-block class=i1 onclick=p10setIcon(1) onkeypress="if (event.key==\'Enter\') p10setIcon(1)"></div>';
4825 + x += '<div tabindex=0 style=display:inline-block class=i2 onclick=p10setIcon(2) onkeypress="if (event.key==\'Enter\') p10setIcon(2)"></div>';
4826 + x += '<div tabindex=0 style=display:inline-block class=i3 onclick=p10setIcon(3) onkeypress="if (event.key==\'Enter\') p10setIcon(3)"></div>';
4827 + x += '<div tabindex=0 style=display:inline-block class=i4 onclick=p10setIcon(4) onkeypress="if (event.key==\'Enter\') p10setIcon(4)"></div>';
4828 + x += '<div tabindex=0 style=display:inline-block class=i5 onclick=p10setIcon(5) onkeypress="if (event.key==\'Enter\') p10setIcon(5)"></div>';
4829 + x += '<div tabindex=0 style=display:inline-block class=i6 onclick=p10setIcon(6) onkeypress="if (event.key==\'Enter\') p10setIcon(6)"></div><br><br>';
4830 + setDialogMode(2, "Icon Selection", 0, null, x);
4831 + QV('id_dialogclose', true);
4832 + }
4833 +
4834 + function p10setIcon(icon) {
4835 + setDialogMode(0);
4836 + meshserver.send({ action: 'changedevice', nodeid: currentNode._id, icon: icon });
4837 + }
4838 +
4839 + var showEditNodeValueDialog_modes = ["Device Name", "Hostname", "Description", "Tags"];
4840 + var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc', 'tags'];
4841 + var showEditNodeValueDialog_modes3 = ['', '', '', "Tag1, Tag2, Tag3"];
4842 + function showEditNodeValueDialog(mode) {
4843 + if (xxdialogMode) return;
4844 + var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue maxlength=64 placeholder="' + showEditNodeValueDialog_modes3[mode] + '" onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
4845 + setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode);
4846 + var v = currentNode[showEditNodeValueDialog_modes2[mode]];
4847 + if (v == null) v = '';
4848 + if (Array.isArray(v)) { v = v.join(', '); }
4849 + Q('dp10devicevalue').value = v;
4850 + p10editdevicevalueValidate();
4851 + Q('dp10devicevalue').focus();
4852 + }
4853 +
4854 + function showEditNodeValueDialogEx(button, mode) {
4855 + var x = { action: 'changedevice', nodeid: currentNode._id };
4856 + x[showEditNodeValueDialog_modes2[mode]] = Q('dp10devicevalue').value;
4857 + meshserver.send(x);
4858 + }
4859 +
4860 + function p10editdevicevalueValidate(mode, e) {
4861 + var x = ((mode > 1) || (Q('dp10devicevalue').value.length > 0));
4862 + QE('idx_dlgOkButton', x);
4863 + if ((e != null) && (x == true) && (e.keyCode == 13)) { dialogclose(1); }
4864 + }
4865 +
4866 + //
4867 + // DESKTOP
4868 + //
4869 +
4870 + var desktopNode;
4871 + function setupDesktop() {
4872 + // Setup the remote desktop
4873 + if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); desktopNode = null; desktop = null; }
4874 +
4875 + // If the device desktop is already connected in multi-desktop, use that.
4876 + if ((desktopNode != currentNode) || (desktop == null)) {
4877 + var xdesk = multiDesktop[currentNode._id];
4878 + if (xdesk != null) {
4879 + // This device already has a canvas, use it.
4880 + QH('DeskParent', '');
4881 + var c = xdesk.m.CanvasId;
4882 + c.setAttribute('id', 'Desk');
4883 + c.setAttribute('onmousedown', 'dmousedown(event)');
4884 + c.setAttribute('onmouseup', 'dmouseup(event)');
4885 + c.setAttribute('onmousemove', 'dmousemove(event)');
4886 + c.removeAttribute('onclick');
4887 + Q('DeskParent').appendChild(c);
4888 + desktop = xdesk;
4889 + if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
4890 + desktop.onStateChanged = onDesktopStateChange;
4891 + desktopNode = currentNode;
4892 + onDesktopStateChange(desktop, desktop.State);
4893 + delete multiDesktop[currentNode._id];
4894 + } else {
4895 + // Device is not already connected, just setup a blank canvas
4896 + QH('DeskParent', '<canvas id=Desk oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
4897 + desktopNode = currentNode;
4898 + }
4899 + // Setup the mouse wheel
4900 + Q('Desk').addEventListener('DOMMouseScroll', function (e) { return dmousewheel(e); });
4901 + Q('Desk').addEventListener('mousewheel', function (e) { return dmousewheel(e); });
4902 + }
4903 + desktopNode = currentNode;
4904 + updateDesktopButtons();
4905 + deskAdjust();
4906 +
4907 + // On some browsers like IE, we can't save screen shots. Hide the scheenshot/capture buttons.
4908 + if (!Q('Desk')['toBlob']) { QV('deskSaveBtn', false); }
4909 + }
4910 +
4911 + // Show and enable the right buttons
4912 + function updateDesktopButtons() {
4913 + var mesh = meshes[currentNode.meshid];
4914 + var deskState = 0;
4915 + if (desktop != null) { deskState = desktop.State; }
4916 + var meshrights = mesh.links[userinfo._id].rights;
4917 +
4918 + // Show the right buttons
4919 + QV('disconnectbutton1span', (deskState != 0));
4920 + QV('connectbutton1span', (deskState == 0) && ((meshrights & 8) || (meshrights & 256)) && (mesh.mtype == 2) && (currentNode.agent.caps & 1));
4921 + QV('connectbutton1hspan',
4922 + (deskState == 0) &&
4923 + (meshrights & 8) &&
4924 + ((mesh.mtype == 1) ||
4925 + ((currentNode.intelamt != null) &&
4926 + (currentNode.intelamt.state == 2) &&
4927 + (currentNode.intelamt.ver != null) &&
4928 + (typeof currentNode.intelamt.sku == 'number') &&
4929 + ((currentNode.intelamt.sku & 8) != 0))
4930 + )
4931 + );
4932 +
4933 + // Show the right settings
4934 + QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == 0) || (desktop.contype == 2)));
4935 + QV('d7meshkvm', (webRtcDesktop) || ((mesh.mtype == 2) && (currentNode.agent.caps & 1) && ((deskState == false) || (desktop.contype == 1))));
4936 +
4937 + // Enable buttons
4938 + var inputAllowed = (meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) == 0));
4939 + var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable remote desktop
4940 + QE('connectbutton1', online);
4941 + var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
4942 + QE('connectbutton1h', hwonline);
4943 + QE('deskSaveBtn', deskState == 3);
4944 + QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus));
4945 + QV('DeskClip', (currentNode.agent) && (currentNode.agent.id != 11) && (currentNode.agent.id != 16) && ((desktop == null) || (desktop.contype != 2))); // Clipboard not supported on MacOS
4946 + QE('DeskClip', deskState == 3);
4947 + QE('DeskType', deskState == 3);
4948 + QV('DeskWD', inputAllowed);
4949 + QE('DeskWD', deskState == 3);
4950 + QV('deskkeys', inputAllowed);
4951 + QE('deskkeys', deskState == 3);
4952 +
4953 + // Display this only if we have Chat & Notify permissions
4954 + QV('DeskChatButton', ((meshrights & 16384) != 0) && (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
4955 + QV('DeskNotifyButton', ((meshrights & 16384) != 0) && (browserfullscreen == false) && (currentNode.agent) && (currentNode.agent.id < 5) && (inputAllowed) && (mesh.mtype == 2) && online);
4956 +
4957 + QV('DeskToolsButton', (inputAllowed) && (mesh.mtype == 2) && online);
4958 + QV('DeskOpenWebButton', (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
4959 + QV('DeskControlSpan', inputAllowed)
4960 + QV('deskActionsBtn', (browserfullscreen == false));
4961 + QV('deskActionsSettings', (browserfullscreen == false));
4962 + if (meshrights & 8) { Q('DeskControl').checked = (getstore('DeskControl', 1) == 1); } else { Q('DeskControl').checked = false; }
4963 + if (online == false) QV('DeskTools', false);
4964 + }
4965 +
4966 + // Debug
4967 + var autoConnectDesktopTimer = null;
4968 + function autoConnectDesktop(e) { if (autoConnectDesktopTimer == null) { autoConnectDesktopTimer = setInterval(connectDesktop, 100); } else { clearInterval(autoConnectDesktopTimer); autoConnectDesktopTimer = null; } }
4969 +
4970 + function connectDesktop(e, contype) {
4971 + p11clearConsoleMsg();
4972 + if (desktop == null) {
4973 + desktopNode = currentNode;
4974 + if (contype == 2) {
4975 + // Setup the Intel AMT remote desktop
4976 + if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop, 2); return; }
4977 + desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
4978 + desktop.debugmode = debugmode;
4979 + desktop.onStateChanged = onDesktopStateChange;
4980 + desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
4981 + desktop.m.useZRLE = (desktopsettings.encoding < 3);
4982 + desktop.m.localKeyMap = desktopsettings.localkeymap;
4983 + desktop.m.showmouse = desktopsettings.showmouse;
4984 + desktop.m.onScreenSizeChange = deskAdjust;
4985 + desktop.m.onKvmData = function (x) {
4986 + //console.log('onKvmData (' + x.length + '): ' + x);
4987 + // Send the presense probe only once if needed.
4988 + if (x.length == 0) { if (!desktop.m._sentPresence) { desktop.m._sentPresence = true; desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 })); } return; }
4989 + var data = null;
4990 + try { data = JSON.parse(x); } catch (e) { }
4991 + if ((data != null) && (data.action != null)) {
4992 + if (data.action == 'restart') {
4993 + // Clear WebRTC channel
4994 + webRtcDesktopReset();
4995 + desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 }));
4996 + } else if ((data.action == 'present') && (webRtcDesktop == null)) {
4997 + // Setup WebRTC channel
4998 + webRtcDesktop = { platform: data.platform };
4999 + var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] };

This file is too large to show in full.

views/translations/download_fr.handlebars new
+41
@@ -0,0 +1,41 @@
1 +<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
2 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
3 + <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
4 + <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
5 + <meta name="apple-mobile-web-app-capable" content="yes">
6 + <meta name="format-detection" content="telephone=no">
7 + <link type="text/css" href="/styles/style.css" media="screen" rel="stylesheet" title="CSS">
8 + <title>MeshCentral - Download</title>
9 +</head>
10 +<body>
11 + <div id="container" style="max-height:100vh">
12 + <div id="mastheadx"></div>
13 + <div id="masthead" style="background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden">
14 + <div style="float:left;height:66px;color:#c8c8c8;padding-left:20px;padding-top:8px">
15 + <strong><font style="font-size:46px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
16 + </div>
17 + <div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:14px">
18 + <strong><font style="font-size:14px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
19 + </div>
20 + </div>
21 + <div id="page_content" style="max-height:calc(100vh-138px)">
22 + <div id="column_l">
23 + <h1>Download</h1>
24 + <p style="margin-left:20px">{{{message}}}</p>
25 + <br>
26 + </div>
27 + <div id="footer">
28 + <table cellpadding="0" cellspacing="10" style="width:100%">
29 + <tbody><tr>
30 + <td style="text-align:left"></td>
31 + <td style="text-align:right">
32 + {{{rootCertLink}}}
33 + &nbsp;<a href="terms">Terms &amp; Privacy</a>
34 + </td>
35 + </tr>
36 + </tbody></table>
37 + </div>
38 + </div>
39 + </div>
40 +
41 +</body></html>
\ No newline at end of file
views/translations/error404_fr.handlebars new
+132
@@ -0,0 +1,132 @@
1 +<!DOCTYPE html><html><head>
2 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
3 + <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
4 + <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
5 + <meta name="apple-mobile-web-app-capable" content="yes">
6 + <meta name="format-detection" content="telephone=no">
7 + <link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
8 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
9 + <title>MeshCentral - Terms of use</title>
10 +</head>
11 +<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" style="display:none;overflow:hidden">
12 + <div id="container">
13 + <!-- Begin Masthead -->
14 + <div id="masthead" class="noselect" style="background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden;">
15 + <div style="float:left; height: 66px; color:#c8c8c8; padding-left:20px; padding-top:8px">
16 + <strong><font style="font-size:46px; font-family: Arial, Helvetica, sans-serif;">{{{title}}}</font></strong>
17 + </div>
18 + <div style="float:left; height: 66px; color:#c8c8c8; padding-left:5px; padding-top:14px">
19 + <strong><font style="font-size:14px; font-family: Arial, Helvetica, sans-serif;">{{{title2}}}</font></strong>
20 + </div>
21 + <p id="logoutControl" style="color:white;font-size:11px;margin: 10px 10px 0;">{{{logoutControl}}}</p>
22 + </div>
23 + <div id="page_leftbar">
24 + <div style="height:16px"></div>
25 + </div>
26 + <div id="topbar" class="noselect style3" style="height:24px;position:relative">
27 + <div id="uiMenuButton" title="User interface selection" onclick="showUserInterfaceSelectMenu()">
28 + ♦
29 + <div id="uiMenu" style="display:none">
30 + <div id="uiViewButton1" class="uiSelector" onclick="userInterfaceSelectMenu(1)" title="Left bar interface"><div class="uiSelector1"></div></div>
31 + <div id="uiViewButton2" class="uiSelector" onclick="userInterfaceSelectMenu(2)" title="Top bar interface"><div class="uiSelector2"></div></div>
32 + <div id="uiViewButton3" class="uiSelector" onclick="userInterfaceSelectMenu(3)" title="Fixed width interface"><div class="uiSelector3"></div></div>
33 + <div id="uiViewButton4" class="uiSelector" onclick="toggleNightMode()" title="Basculer mode nuit"><div class="uiSelector4"></div></div>
34 + </div>
35 + </div>
36 + </div>
37 + <div id="column_l" style="max-height:calc(100vh - 135px);overflow-y:auto">
38 + <div style="text-align:center;padding-top:30px;font-size:200px;font-family:Arial;color:#bbb"><b>404</b></div>
39 + <div style="text-align:center;font-size:20px;font-family:Arial;color:#999">This page does not exist</div>
40 + <div style="text-align:center;padding-top:20px;font-size:20px;font-family:Arial;color:#999"><a href="/" style="text-decoration:none"><b>Go to main site</b></a></div>
41 + </div>
42 + <div id="footer">
43 + <table cellpadding="0" cellspacing="10" style="width: 100%">
44 + <tbody><tr>
45 + <td style="text-align:left"></td>
46 + <td style="text-align:right"><a href="/">Retour</a></td>
47 + </tr>
48 + </tbody></table>
49 + </div>
50 + </div>
51 + <script>
52 + 'use strict';
53 + var uiMode = parseInt(getstore('uiMode', 1));
54 + var webPageStackMenu = false;
55 + var webPageFullScreen = true;
56 + var nightMode = (getstore('_nightMode', '0') == '1');
57 +
58 + var terms = '{{{terms}}}';
59 + if (terms != '') { QH('column_l', decodeURIComponent(terms)); }
60 + QV('column_l', true);
61 + userInterfaceSelectMenu();
62 +
63 + // Toggle user interface menu
64 + function showUserInterfaceSelectMenu() {
65 + Q('uiViewButton1').classList.remove('uiSelectorSel');
66 + Q('uiViewButton2').classList.remove('uiSelectorSel');
67 + Q('uiViewButton3').classList.remove('uiSelectorSel');
68 + Q('uiViewButton4').classList.remove('uiSelectorSel');
69 + try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
70 + QV('uiMenu', (QS('uiMenu').display == 'none'));
71 + if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
72 + }
73 +
74 + function userInterfaceSelectMenu(s) {
75 + if (s) { uiMode = s; putstore('uiMode', uiMode); }
76 + webPageFullScreen = (uiMode < 3);
77 + webPageStackMenu = true;//(uiMode > 1);
78 + toggleFullScreen(0);
79 + toggleStackMenu(0);
80 + QC('column_l').add('room4submenu');
81 + }
82 +
83 + function toggleNightMode() {
84 + nightMode = !nightMode;
85 + if (nightMode) { QC('body').add('night'); } else { QC('body').remove('night'); }
86 + putstore('_nightMode', nightMode ? '1' : '0');
87 + }
88 +
89 + // Toggle the web page to full screen
90 + function toggleFullScreen(toggle) {
91 + if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
92 + var hide = 0;
93 + //if (args.hide) { hide = parseInt(args.hide); }
94 + if (webPageFullScreen == false) {
95 + QC('body').remove('menu_stack');
96 + QC('body').remove('fullscreen');
97 + QC('body').remove('arg_hide');
98 + //if (xxcurrentView >= 10) QC('column_l').add('room4submenu');
99 + //QV('UserDummyMenuSpan', false);
100 + //QV('page_leftbar', false);
101 + } else {
102 + QC('body').add('fullscreen');
103 + if (hide & 16) QC('body').add('arg_hide'); // This is replacement for QV('page_leftbar', !(hide & 16));
104 + //QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
105 + //QV('page_leftbar', true);
106 + }
107 + QV('body', true);
108 + }
109 +
110 + // If FullScreen, toggle menu to be horisontal or vertical
111 + function toggleStackMenu(toggle) {
112 + if (webPageFullScreen == true) {
113 + if (toggle === 1) {
114 + webPageStackMenu = !webPageStackMenu;
115 + putstore('webPageStackMenu', webPageStackMenu);
116 + }
117 + if (webPageStackMenu == false) {
118 + QC('body').remove('menu_stack');
119 + } else {
120 + QC('body').add('menu_stack');
121 + //if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
122 + }
123 + }
124 + }
125 +
126 + function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
127 + function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
128 +
129 + </script>
130 +
131 +
132 +</body></html>
\ No newline at end of file
views/translations/login-mobile_fr.handlebars new
+631
@@ -0,0 +1,631 @@
1 +<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
2 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
3 + <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
4 + <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
5 + <meta name="apple-mobile-web-app-capable" content="yes">
6 + <meta name="format-detection" content="telephone=no">
7 + <link rel="shortcut icon" type="image/x-icon" href="{{{domainurl}}}favicon.ico">
8 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
9 + <script type="text/javascript" src="scripts/u2f-api.js"></script>
10 + <title>MeshCentral - Login</title>
11 + <style>
12 + a {
13 + color: #036;
14 + text-decoration: underline;
15 + }
16 +
17 + #footer a {
18 + color: #fff;
19 + text-decoration: underline;
20 + }
21 +
22 + #footer a:hover {
23 + color: #fff;
24 + text-decoration: none;
25 + }
26 + </style>
27 +</head>
28 +<body onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;margin:0;padding:0;border:0;color:black;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
29 + <div id="container">
30 + <div id="mastheadx"></div>
31 + <div id="masthead" style="background:url(logo.png) 0px 0px;background-size:341px 50px;background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden">
32 + <div style="float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:6px">
33 + <strong><font style="font-size:36px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
34 + </div>
35 + <div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:10px">
36 + <strong><font style="font-size:12px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
37 + </div>
38 + </div>
39 + <div id="page_content" style="overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%;display:flex;align-items:center">
40 + <div id="column_l" style="padding:10px;width:100%">
41 + <table style="width:100%">
42 + <tbody><tr>
43 + <td align="center">
44 + <div id="loginpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;display:none">
45 + <form method="post">
46 + <input type="hidden" name="action" value="login">
47 + <div id="message1">
48 + {{{message}}}
49 + </div>
50 + <div>
51 + <b>Log In</b>
52 + </div>
53 + <table>
54 + <tbody><tr>
55 + <td id="loginusername" align="right" width="100">Nom d'utilisateur:</td>
56 + <td><input id="username" type="text" maxlength="64" name="username" onchange="validateLogin(1)" onkeyup="validateLogin(1,event)"></td>
57 + </tr>
58 + <tr>
59 + <td align="right">Password:</td>
60 + <td><input id="password" type="password" maxlength="256" name="password" autocomplete="off" onchange="validateLogin(2)" onkeyup="validateLogin(2,event)"></td>
61 + </tr>
62 + <tr>
63 + <td><div id="showPassHintLink" style="display:none"><a onclick="showPassHint()" style="cursor:pointer">Show Hint</a></div></td>
64 + <td align="right"><input id="loginButton" type="submit" value="Log In" disabled="disabled"></td>
65 + </tr>
66 + </tbody></table>
67 + <div id="hrAccountDiv" style="display:none"><hr></div>
68 + <div id="resetAccountDiv" style="display:none;padding:2px">
69 + <span id="resetAccountSpan">Forgot user/password?</span> <a onclick="xgo(3)" style="cursor:pointer">Reset account</a>.
70 + </div>
71 + <div id="newAccountDiv" style="display:none;padding:2px">
72 + Don't have an account? <a onclick="xgo(2)" style="cursor:pointer">Create one</a>.
73 + </div>
74 + <input id="loginformargs" name="urlargs" type="hidden" value="">
75 + </form>
76 + </div>
77 + <div id="createpanel" style="display:none">
78 + <div style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;position:relative">
79 + <form method="post">
80 + <input type="hidden" name="action" value="createaccount">
81 + <div id="message2">
82 + {{{message}}}
83 + </div>
84 + <div>
85 + <b>Account Creation</b>
86 + </div>
87 + <div id="passwordPolicyCallout" style="left:-5px;top:10px;width:100px;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
88 + <table>
89 + <tbody><tr id="nuUserRow">
90 + <td align="right" width="100">Nom d'utilisateur:</td>
91 + <td><input id="ausername" type="text" name="username" onchange="validateCreate(1)" maxlength="64" onkeydown="haltReturn(event)" onkeyup="validateCreate(1,event)"></td>
92 + </tr>
93 + <tr>
94 + <td align="right" width="100">Email:</td>
95 + <td><input id="aemail" type="text" name="email" onchange="validateCreate(2)" maxlength="256" onkeydown="haltReturn(event)" onkeyup="validateCreate(2,event)"></td>
96 + </tr>
97 + <tr>
98 + <td align="right">Password:</td>
99 + <td><input id="apassword1" type="password" name="password1" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(3)" onkeyup="validateCreate(3,event)"></td>
100 + </tr>
101 + <tr>
102 + <td align="right">Password:</td>
103 + <td><input id="apassword2" type="password" name="password2" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(4)" onkeyup="validateCreate(4,event)"></td>
104 + </tr>
105 + <tr id="createPanelHint" style="display:none">
106 + <td align="right">Pass Hint:</td>
107 + <td><input id="apasswordhint" type="text" name="apasswordhint" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(5)" onkeyup="validateCreate(5,event)"></td>
108 + </tr>
109 + <tr id="newAccountPass" title="Enter the account creation token">
110 + <td align="right">Creation Token:</td>
111 + <td><input id="anewaccountpass" type="password" name="anewaccountpass" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(6)" onkeyup="validateCreate(6,event)"></td>
112 + </tr>
113 + <tr>
114 + <td colspan="2">
115 + <div style="float:right"><input id="createButton" type="submit" value="Create Account" disabled="disabled"></div>
116 + <div id="passWarning" style="padding-top:6px"></div>
117 + </td>
118 + </tr>
119 + </tbody></table>
120 + <hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
121 + <input id="createformargs" name="urlargs" type="hidden" value="">
122 + </form>
123 + </div>
124 + </div>
125 + <div id="resetpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
126 + <form method="post">
127 + <input type="hidden" name="action" value="resetaccount">
128 + <div id="message3">
129 + {{{message}}}
130 + </div>
131 + <div>
132 + <b>Account Reset</b>
133 + </div>
134 + <table>
135 + <tbody><tr>
136 + <td align="right" width="100">Email:</td>
137 + <td><input id="remail" type="text" name="email" maxlength="256" onchange="validateReset()" onkeyup="validateReset(event)"></td>
138 + </tr>
139 + <tr>
140 + <td colspan="2">
141 + <div style="float:right"><input id="eresetButton" type="submit" value="Reset Account" disabled="disabled"></div>
142 + <div id="passWarning" style="padding-top:6px"></div>
143 + </td>
144 + </tr>
145 + </tbody></table>
146 + <hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
147 + <input id="resetformargs" name="urlargs" type="hidden" value="">
148 + </form>
149 + </div>
150 + <div id="tokenpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
151 + <form method="post" autocomplete="off">
152 + <input type="hidden" name="action" value="tokenlogin">
153 + <input type="hidden" name="hwstate" value="{{{hwstate}}}">
154 + <div id="message4">
155 + {{{message}}}
156 + </div>
157 + <table>
158 + <tbody><tr>
159 + <td align="right" width="100">Login token:</td>
160 + <td>
161 + <input id="tokenInput" type="text" name="token" maxlength="50" onchange="checkToken(event)" onkeyup="checkToken(event)" onkeydown="checkToken(event)" onfocus="checkTokenTimer(1)" onblur="checkTokenTimer(0)">
162 + <input id="hwtokenInput" type="text" name="hwtoken" style="display:none">
163 + </td>
164 + </tr>
165 + <tr>
166 + <td colspan="2">
167 + <div style="float:right"><input id="tokenOkButton" type="submit" value="Login" disabled="disabled"></div>
168 + </td>
169 + </tr>
170 + </tbody></table>
171 + <hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
172 + <input id="tokenformargs" name="urlargs" type="hidden" value="">
173 + </form>
174 + </div>
175 +
176 + <div id="resettokenpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
177 + <form method="post" autocomplete="off">
178 + <input type="hidden" name="action" value="resetaccount">
179 + <div id="message5">
180 + {{{message}}}
181 + </div>
182 + <table>
183 + <tbody><tr>
184 + <td align="right" width="100">Login token:</td>
185 + <td>
186 + <input id="resetTokenInput" type="text" name="token" maxlength="50" onchange="resetCheckToken(event)" onpaste="resetCheckToken(event)" onkeyup="resetCheckToken(event)" onkeydown="resetCheckToken(event)">
187 + <input id="resetHwtokenInput" type="text" name="hwtoken" style="display:none">
188 + </td>
189 + </tr>
190 + <tr>
191 + <td colspan="2">
192 + <div style="float:right"><input id="resetTokenOkButton" type="submit" value="Login" disabled="disabled"></div>
193 + </td>
194 + </tr>
195 + </tbody></table>
196 + <hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
197 + <input id="resettokenformargs" name="urlargs" type="hidden" value="">
198 + </form>
199 + </div>
200 +
201 + <div id="resetpasswordpanel" style="position:relative;background-color:#979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
202 + <form method="post">
203 + <input type="hidden" name="action" value="resetpassword">
204 + <div id="message6">
205 + {{{message}}}
206 + </div>
207 + <div id="rpasswordPolicyCallout" style="left:-10px;width:100px;display:none;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
208 + <table>
209 + <tbody><tr>
210 + <td id="rnuPass1" width="100" align="right">Password:</td>
211 + <td><input id="rapassword1" type="password" name="rpassword1" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(3,event)" onkeyup="validatePassReset(3,event)"></td>
212 + </tr>
213 + <tr>
214 + <td id="rnuPass2" align="right">Password:</td>
215 + <td><input id="rapassword2" type="password" name="rpassword2" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(4,event)" onkeyup="validatePassReset(4,event)"></td>
216 + </tr>
217 + <tr id="resetpasswordpanelHint" style="display:none">
218 + <td id="rnuHint" align="right">Password Hint:</td>
219 + <td><input id="rapasswordhint" type="text" name="rpasswordhint" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(5,event)" onkeyup="validatePassReset(5,event)"></td>
220 + </tr>
221 + <tr>
222 + <td colspan="2">
223 + <div style="float:right"><input id="resetPassButton" type="submit" value="Reset Password" disabled="disabled"></div>
224 + <div id="rpassWarning" style="padding-top:6px"></div>
225 + </td>
226 + </tr>
227 + </tbody></table>
228 + <hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
229 + <input id="resetpasswordformargs" name="urlargs" type="hidden" value="">
230 + </form>
231 + </div>
232 +
233 + </td>
234 + </tr>
235 + </tbody></table>
236 + </div>
237 + </div>
238 + <div id="footer" style="height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px">
239 + <table cellpadding="0" cellspacing="6" style="width:100%">
240 + <tbody><tr>
241 + <td style="text-align:left;color:white">{{{footer}}}</td>
242 + <td style="text-align:right">{{{rootCertLink}}}&nbsp;<a href="terms">Terms &amp; Privacy</a></td>
243 + </tr>
244 + </tbody></table>
245 + </div>
246 + </div>
247 + <div id="dialog" style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:180px;width:400px;display:none">
248 + <div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
249 + <div id="id_dialogclose" style="float:right;padding:5px;cursor:pointer" onclick="setDialogMode()"><b>X</b></div>
250 + <div id="id_dialogtitle" style="padding:5px"></div>
251 + <div style="width:100%;margin:6px"></div>
252 + </div>
253 + <div style="margin-right:16px;margin-left:8px">
254 + <div id="dialog1" style="margin:auto;text-align:center;margin:3px">
255 + <div id="id_dialogMessage" style="padding:10px"></div>
256 + </div>
257 + <div id="dialog2" style="margin:auto;margin:3px">
258 + <div id="id_dialogOptions"></div>
259 + </div>
260 + </div>
261 + <div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:20px">
262 + <input id="idx_dlgCancelButton" type="button" value="Annuler" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">
263 + <input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)">
264 + </div>
265 + </div>
266 + <script>
267 + 'use strict';
268 + var passhint = '{{{passhint}}}';
269 + var newAccountPass = parseInt('{{{newAccountPass}}}');
270 + var emailCheck = ('{{{emailcheck}}}' == 'true');
271 + var features = parseInt('{{{features}}}');
272 + var passRequirements = '{{{passRequirements}}}';
273 + if (passRequirements != '') { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); } else { passRequirements = {}; }
274 + var passRequirementsEx = ((passRequirements.min != null) || (passRequirements.max != null) || (passRequirements.upper != null) || (passRequirements.lower != null) || (passRequirements.numeric != null) || (passRequirements.nonalpha != null));
275 + var hardwareKeyChallenge = decodeURIComponent('{{{hkey}}}');
276 + var currentpanel = 0;
277 +
278 + // If URL arguments are provided, add them to form posts
279 + if (window.location.href.indexOf('?') > 0) {
280 + var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
281 + Q('loginformargs').value = urlargs;
282 + Q('createformargs').value = urlargs;
283 + Q('resetformargs').value = urlargs;
284 + Q('tokenformargs').value = urlargs;
285 + Q('resettokenformargs').value = urlargs;
286 + Q('resetpasswordformargs').value = urlargs;
287 + }
288 +
289 + function startup() {
290 + if ((features & 32) == 0) {
291 + // Guard against other site's top frames (web bugs).
292 + var loc = null;
293 + try { loc = top.location.toString().toLowerCase(); } catch (e) { }
294 + if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
295 + }
296 +
297 + if (features & 0x200000) { // Email is username
298 + QH('loginusername', "Email:");
299 + QH('resetAccountSpan', "Forgot password?");
300 + QV('nuUserRow', false);
301 + }
302 +
303 + QV('createPanelHint', passRequirements.hint === true);
304 + QV('resetpasswordpanelHint', passRequirements.hint === true);
305 +
306 + window.onresize = center;
307 + center();
308 + validateLogin();
309 + validateCreate();
310 + if ('{{loginmode}}' != '') { go(parseInt('{{loginmode}}')); } else { go(1); }
311 + QV('newAccountDiv', ('{{{newAccount}}}' === '1') || ('{{{newAccount}}}' === 'true')); // If new accounts are not allowed, don't display the new account link.
312 + if ((passRequirements.hint === true) && (passhint != null) && (passhint.length > 0)) { QV('showPassHintLink', true); }
313 + QV('newAccountPass', (newAccountPass == 1));
314 + QV('resetAccountDiv', (emailCheck == true));
315 + QV('hrAccountDiv', (emailCheck == true) || (newAccountPass == 1));
316 +
317 + if ('{{loginmode}}' == '4') {
318 + try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
319 + if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
320 + hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer;
321 +
322 + var publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
323 + for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
324 + publicKeyCredentialRequestOptions.allowCredentials.push(
325 + { id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
326 + );
327 + }
328 +
329 + // New WebAuthn hardware keys
330 + navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
331 + function (rawAssertion) {
332 + var assertion = {
333 + id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
334 + clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
335 + userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
336 + signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
337 + authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
338 + };
339 + Q('hwtokenInput').value = JSON.stringify(assertion);
340 + QE('tokenOkButton', true);
341 + Q('tokenOkButton').click();
342 + },
343 + function (error) { console.log('credentials-get error', error); }
344 + );
345 + }
346 + }
347 +
348 + if ('{{loginmode}}' == '5') {
349 + try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
350 + if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
351 + hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer;
352 +
353 + var publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
354 + for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
355 + publicKeyCredentialRequestOptions.allowCredentials.push(
356 + { id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
357 + );
358 + }
359 +
360 + // New WebAuthn hardware keys
361 + navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
362 + function (rawAssertion) {
363 + var assertion = {
364 + id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
365 + clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
366 + userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
367 + signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
368 + authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
369 + };
370 + Q('resetHwtokenInput').value = JSON.stringify(assertion);
371 + QE('resetTokenOkButton', true);
372 + Q('resetTokenOkButton').click();
373 + },
374 + function (error) { console.log('credentials-get error', error); }
375 + );
376 + }
377 + }
378 + }
379 +
380 + function showPassHint() {
381 + if (passRequirements.hint === true) { messagebox("Password Hint", passhint); }
382 + }
383 +
384 + function xgo(x) {
385 + QV('message1', false);
386 + QV('message2', false);
387 + QV('message3', false);
388 + QV('message4', false);
389 + QV('message5', false);
390 + QV('message6', false);
391 + go(x);
392 + }
393 +
394 + function go(x) {
395 + currentpanel = x;
396 + setDialogMode(0);
397 + QV('showPassHintLink', false);
398 + QV('loginpanel', x == 1);
399 + QV('createpanel', x == 2);
400 + QV('resetpanel', x == 3);
401 + QV('tokenpanel', x == 4);
402 + QV('resettokenpanel', x == 5);
403 + QV('resetpasswordpanel', x == 6);
404 + if (x == 1) { Q('username').focus(); }
405 + if (x == 2) { if (features & 0x200000) { Q('aemail').focus(); } else { Q('ausername').focus(); } } // Email is username
406 + if (x == 3) { Q('remail').focus(); }
407 + if (x == 4) { Q('tokenInput').focus(); }
408 + if (x == 5) { Q('resetTokenInput').focus(); }
409 + if (x == 6) { Q('rapassword1').focus(); }
410 + }
411 +
412 + function validateLogin(box, e) {
413 + var ok = ((Q('username').value.length > 0) && (Q('username').value.indexOf(' ') == -1) && (Q('password').value.length > 0));
414 + QE('loginButton', ok);
415 + setDialogMode(0);
416 + if ((e != null) && (e.keyCode == 13)) { if (box == 1) { Q('password').focus(); } else if (box == 2) { Q('loginButton').click(); } }
417 + if (e != null) { haltEvent(e); }
418 + }
419 +
420 + function validateCreate(box,e) {
421 + setDialogMode(0);
422 + var ok = false;
423 + if (features & 0x200000) { ok = true; } else { ok = (Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (Q('ausername').value.indexOf('"') == -1) && (Q('ausername').value.indexOf(',') == -1); }
424 + ok &= ((validateEmail(Q('aemail').value) == true) && (Q('apassword1').value.length > 0) && (Q('apassword2').value == Q('apassword1').value));
425 + if ((newAccountPass == 1) && (Q('anewaccountpass').value.length == 0)) { ok = false; }
426 + if (Q('apassword1').value == '') {
427 + QH('passWarning', '');
428 + QV('passwordPolicyCallout', false);
429 + } else {
430 + if (!passRequirementsEx) {
431 + // No password requirements, display password strength
432 + var passStrength = checkPasswordStrength(Q('apassword1').value);
433 + if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>' + "Mot de passe fort" + '</b><span>'); }
434 + else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>' + "Good Password" + '</b><span>'); }
435 + else { QH('passWarning', '<span style=color:red><b>' + "Mot de passe faible" + '</b><span>'); }
436 + } else {
437 + // Password requirements provided, use that
438 + var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
439 + if (passReq == false) {
440 + ok = false;
441 + //QS('nuPass1').color = '#7b241c';
442 + //QS('nuPass2').color = '#7b241c';
443 + QH('passWarning', '<span style=color:red><b>' + "Password Policy" + '</b><span>'); // TODO: Display problem hint
444 + QV('passwordPolicyCallout', true);
445 + QH('passwordPolicyCallout', passwordPolicyText(Q('apassword1').value));
446 + } else {
447 + QH('passWarning', '');
448 + QV('passwordPolicyCallout', false);
449 + }
450 + }
451 + }
452 + QE('createButton', ok);
453 + if ((e != null) && (e.keyCode == 13)) {
454 + if (box == 1) { Q('aemail').focus(); }
455 + if (box == 2) { Q('apassword1').focus(); }
456 + if (box == 3) { Q('apassword2').focus(); }
457 + if (box == 4) { Q('apasswordhint').focus(); }
458 + if (box == 5) { if (newAccountPass == 1) { Q('anewaccountpass').focus(); } else { Q('createButton').click(); } }
459 + if (box == 6) { Q('createButton').click(); }
460 + }
461 + if (e != null) { haltEvent(e); }
462 + }
463 +
464 + function validatePassReset(box, e) {
465 + setDialogMode(0);
466 + var pass1ok = (Q('rapassword1').value.length > 0);
467 + var pass2ok = (Q('rapassword2').value.length > 0) && (Q('rapassword2').value == Q('rapassword1').value);
468 + var ok = (pass1ok && pass2ok);
469 +
470 + // Color the fields
471 + QS('rnuPass1').color = pass1ok ? 'black' : '#7b241c';
472 + QS('rnuPass2').color = pass2ok ? 'black' : '#7b241c';
473 +
474 + if (Q('rapassword1').value == '') {
475 + QH('rpassWarning', '');
476 + QV('rpasswordPolicyCallout', false);
477 + } else {
478 + if (!passRequirementsEx) {
479 + // No password requirements, display password strength
480 + var passStrength = checkPasswordStrength(Q('rapassword1').value);
481 + if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>' + "Mot de passe fort" + '</b><span>'); }
482 + else if (passStrength >= 60) { QH('rpassWarning', '<span style=color:blue><b>' + "Good Password" + '</b><span>'); }
483 + else { QH('rpassWarning', '<span style=color:red><b>' + "Mot de passe faible" + '</b><span>'); }
484 + } else {
485 + // Password requirements provided, use that
486 + var passReq = checkPasswordRequirements(Q('rapassword1').value, passRequirements);
487 + if (passReq == false) {
488 + ok = false;
489 + QS('rnuPass1').color = '#7b241c';
490 + QS('rnuPass2').color = '#7b241c';
491 + QH('rpassWarning', '<div style=color:red;cursor:pointer onclick=showPasswordPolicy()><b>' + "Password Policy" + '</b><div>'); // This is also a link to the password policy
492 + QV('rpasswordPolicyCallout', true);
493 + QH('rpasswordPolicyCallout', passwordPolicyText(Q('rapassword1').value));
494 + } else {
495 + QH('rpassWarning', '');
496 + QV('rpasswordPolicyCallout', false);
497 + }
498 + }
499 + }
500 + if ((e != null) && (e.keyCode == 13)) {
501 + if (box == 2) { Q('rapassword1').focus(); }
502 + if (box == 3) { Q('rapassword2').focus(); }
503 + if (box == 4) { Q('rapasswordhint').focus(); }
504 + if (box == 6) { Q('resetPassButton').click(); }
505 + }
506 + if (e != null) { haltEvent(e); }
507 + QE('resetPassButton', ok);
508 + }
509 +
510 + function validateReset(e) {
511 + setDialogMode(0);
512 + var x = validateEmail(Q('remail').value);
513 + QE('eresetButton', x);
514 + if ((e != null) && (e.keyCode == 13) && (x == true)) { Q('eresetButton').click(); }
515 + if (e != null) { haltEvent(e); }
516 + }
517 +
518 + function passwordPolicyText(pass) {
519 + var policy = '<div style=text-align:left>';
520 + var counts = strCount(pass);
521 + if (passRequirements.min && ((pass == null) || (pass.length < passRequirements.min))) { policy += format("Minimum length of {0}", passRequirements.min) + '<br />'; }
522 + if (passRequirements.max && ((pass == null) || (pass.length > passRequirements.max))) { policy += format("Maximum length of {0}", passRequirements.max) + '<br />'; }
523 + if (passRequirements.upper && ((pass == null) || (counts.upper < passRequirements.upper))) { policy += format("{0} upper case", passRequirements.upper) + '<br />'; }
524 + if (passRequirements.lower && ((pass == null) || (counts.lower < passRequirements.lower))) { policy += format("{0} lower case", passRequirements.lower) + '<br />'; }
525 + if (passRequirements.numeric && ((pass == null) || (counts.numeric < passRequirements.numeric))) { policy += format("{0} numeric", passRequirements.numeric) + '<br />'; }
526 + if (passRequirements.nonalpha && ((pass == null) || (counts.nonalpha < passRequirements.nonalpha))) { policy += format("{0} non-alphanumeric", passRequirements.nonalpha) + '<br />'; }
527 + policy += '</div>';
528 + return policy;
529 + }
530 +
531 + // Return a password strength score
532 + function checkPasswordStrength(password) {
533 + var r = 0, letters = {}, varCount = 0, variations = { digits: /\d/.test(password), lower: /[a-z]/.test(password), upper: /[A-Z]/.test(password), nonWords: /\W/.test(password) }
534 + if (!password) return 0;
535 + for (var i = 0; i< password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; }
536 + for (var c in variations) { varCount += (variations[c] == true) ? 1 : 0; }
537 + return parseInt(r + (varCount - 1) * 10);
538 + }
539 +
540 + // Check password requirements
541 + function checkPasswordRequirements(password, requirements) {
542 + if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
543 + if (requirements.min) { if (password.length < requirements.min) return false; }
544 + if (requirements.max) { if (password.length > requirements.max) return false; }
545 + var counts = strCount(password);
546 + if (requirements.numeric && (counts.numeric < requirements.numeric)) return false;
547 + if (requirements.lower && (counts.lower < requirements.lower)) return false;
548 + if (requirements.upper && (counts.upper < requirements.upper)) return false;
549 + if (requirements.nonalpha && (counts.nonalpha < requirements.nonalpha)) return false;
550 + return true;
551 + }
552 +
553 + function strCount(password) {
554 + var counts = { numeric: 0, lower: 0, upper: 0, nonalpha: 0 };
555 + if (typeof password != 'string') return counts;
556 + for (var i = 0; i < password.length; i++) {
557 + if (/\d/.test(password[i])) { counts.numeric++; }
558 + if (/[a-z]/.test(password[i])) { counts.lower++; }
559 + if (/[A-Z]/.test(password[i])) { counts.upper++; }
560 + if (/\W/.test(password[i])) { counts.nonalpha++; }
561 + }
562 + return counts;
563 + }
564 +
565 + var xcheckTokenTimer = null;
566 + function checkTokenTimer(enter) {
567 + if ((enter == 0) && (xcheckTokenTimer != null)) { clearInterval(xcheckTokenTimer); xcheckTokenTimer = null; }
568 + if ((enter == 1) && (xcheckTokenTimer == null)) { xcheckTokenTimer = setInterval(checkToken, 200); }
569 + }
570 +
571 + function checkToken() {
572 + var t1 = Q('tokenInput').value, t2 = t1.split(' ').join('');
573 + if (t1 != t2) { Q('tokenInput').value = t2; }
574 + QE('tokenOkButton', (Q('tokenInput').value.length == 6) || (Q('tokenInput').value.length == 8) || (Q('tokenInput').value.length == 44));
575 + }
576 +
577 + function resetCheckToken() {
578 + var t1 = Q('resetTokenInput').value, t2 = t1.split(' ').join('');
579 + if (t1 != t2) { Q('resetTokenInput').value = t2; }
580 + QE('resetTokenOkButton', (Q('resetTokenInput').value.length == 6) || (Q('resetTokenInput').value.length == 8) || (Q('resetTokenInput').value.length == 44));
581 + }
582 +
583 + //
584 + // POPUP DIALOG
585 + //
586 +
587 + // undefined = Hidden, 1 = Generic Message
588 + var xxdialogMode;
589 + var xxdialogFunc;
590 + var xxdialogButtons;
591 + var xxdialogTag;
592 + var xxcurrentView = 0;
593 +
594 + // Display a dialog box
595 + // Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
596 + function setDialogMode(x, y, b, f, c, tag) {
597 + xxdialogMode = x;
598 + xxdialogFunc = f;
599 + xxdialogButtons = b;
600 + xxdialogTag = tag;
601 + QE('idx_dlgOkButton', true);
602 + QV('idx_dlgOkButton', b & 1);
603 + QV('idx_dlgCancelButton', b & 2);
604 + QV('id_dialogclose', (b & 2) || (b & 8));
605 + QV('idx_dlgButtonBar', b & 7);
606 + if (y) QH('id_dialogtitle', y);
607 + for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
608 + QV('dialog', x);
609 + if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
610 + }
611 +
612 + function dialogclose(x) {
613 + var f = xxdialogFunc;
614 + var b = xxdialogButtons;
615 + var t = xxdialogTag;
616 + setDialogMode();
617 + if (((b & 8) || x) && f) f(x, t);
618 + }
619 +
620 + function center() { QS('dialog').left = ((((getDocWidth() - 400) / 2)) + 'px'); }
621 + function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
622 + function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
623 + function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
624 + function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
625 + function haltReturn(e) { if (e.keyCode == 13) { haltEvent(e); } }
626 + function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
627 + function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
628 +
629 + </script>
630 +
631 +</body></html>
\ No newline at end of file
views/translations/login_fr.handlebars new
+712
@@ -0,0 +1,712 @@
1 +<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
2 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
3 + <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
4 + <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
5 + <meta name="apple-mobile-web-app-capable" content="yes">
6 + <meta name="format-detection" content="telephone=no">
7 + <link rel="shortcut icon" type="image/x-icon" href="{{{domainurl}}}favicon.ico">
8 + <link keeplink="1" type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
9 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
10 + <script keeplink="1" type="text/javascript" src="scripts/u2f-api.js"></script>
11 + <title>{{{title}}} - Login</title>
12 +</head>
13 +<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" class="arg_hide login">
14 + <div id="container">
15 + <div id="masthead">
16 + <div class="title">{{{title}}}</div>
17 + <div class="title2">{{{title2}}}</div>
18 + </div>
19 + <div id="topbar" class="noselect style3" style="height:24px">
20 + <div id="uiMenuButton" title="User interface selection" onclick="showUserInterfaceSelectMenu()">
21 + ♦
22 + <div id="uiMenu" style="display:none">
23 + <div id="uiViewButton1" class="uiSelector" onclick="userInterfaceSelectMenu(1)" title="Left bar interface"><div class="uiSelector1"></div></div>
24 + <div id="uiViewButton2" class="uiSelector" onclick="userInterfaceSelectMenu(2)" title="Top bar interface"><div class="uiSelector2"></div></div>
25 + <div id="uiViewButton3" class="uiSelector" onclick="userInterfaceSelectMenu(3)" title="Fixed width interface"><div class="uiSelector3"></div></div>
26 + <div id="uiViewButton4" class="uiSelector" onclick="toggleNightMode()" title="Basculer mode nuit"><div class="uiSelector4"></div></div>
27 + </div>
28 + </div>
29 + </div>
30 + <div id="column_l">
31 + <h1>Bienvenue</h1>
32 + <div id="welcomeText" style="display:none">Connect to your home or office devices from anywhere in the world using <a href="http://www.meshcommander.com/meshcentral2">MeshCentral</a>, the real time, open source remote monitoring and management web site. You will need to download and install a management agent on your computers. Once installed, computers will show up in the "My Devices" section of this web site and you will be able to monitor them and take control of them.</div>
33 + <table id="centralTable" style="">
34 + <tbody><tr>
35 + <td id="welcomeimage">
36 + <picture>
37 + <img alt="" src="welcome.jpg" style="border-radius:20px">
38 + </picture>
39 + </td>
40 + <td id="logincell">
41 + <div id="loginpanel" style="display:none">
42 + <form method="post">
43 + <input type="hidden" name="action" value="login">
44 + <div id="message1">
45 + {{{message}}}
46 + </div>
47 + <div>
48 + <b>Log In</b>
49 + </div>
50 + <table>
51 + <tbody><tr>
52 + <td id="loginusername" align="right" width="100">Nom d'utilisateur:</td>
53 + <td><input id="username" type="text" maxlength="64" name="username" onchange="validateLogin(1)" onkeyup="validateLogin(1,event)"></td>
54 + </tr>
55 + <tr>
56 + <td align="right">Password:</td>
57 + <td><input id="password" type="password" maxlength="256" name="password" autocomplete="off" onchange="validateLogin(2)" onkeyup="validateLogin(2,event)"></td>
58 + </tr>
59 + <tr>
60 + <td><div id="showPassHintLink" style="display:none"><a onclick="return showPassHint(event);" href="#" style="cursor:pointer">Show Hint</a></div></td>
61 + <td align="right"><input id="loginButton" type="submit" value="Log In" disabled="disabled"></td>
62 + </tr>
63 + </tbody></table>
64 + <div id="hrAccountDiv" style="display:none"><hr></div>
65 + <div id="resetAccountDiv" style="display:none;padding:2px">
66 + <span id="resetAccountSpan">Forgot username/password?</span> <a onclick="return xgo(3,event);" href="#" style="cursor:pointer">Reset account</a>.
67 + </div>
68 + <div id="newAccountDiv" style="display:none;padding:2px">
69 + Don't have an account? <a onclick="return xgo(2,event);" href="#" style="cursor:pointer">Create one</a>.
70 + </div>
71 + <input id="loginformargs" name="urlargs" type="hidden" value="">
72 + </form>
73 + </div>
74 + <div id="createpanel" style="display:none;position:relative">
75 + <form method="post">
76 + <input type="hidden" name="action" value="createaccount">
77 + <div id="message2">
78 + {{{message}}}
79 + </div>
80 + <div>
81 + <b>Account Creation</b>
82 + </div>
83 + <div id="passwordPolicyCallout" style="display:none"></div>
84 + <table>
85 + <tbody><tr id="nuUserRow">
86 + <td id="nuUser" align="right" width="100">Nom d'utilisateur:</td>
87 + <td><input id="ausername" type="text" name="username" onchange="validateCreate(1)" maxlength="64" onkeydown="haltReturn(event)" onkeyup="validateCreate(1,event)"></td>
88 + </tr>
89 + <tr>
90 + <td id="nuEmail" align="right" width="100">Email:</td>
91 + <td><input id="aemail" type="text" name="email" onchange="validateCreate(2)" maxlength="256" onkeydown="haltReturn(event)" onkeyup="validateCreate(2,event)"></td>
92 + </tr>
93 + <tr>
94 + <td id="nuPass1" align="right">Password:</td>
95 + <td><input id="apassword1" type="password" name="password1" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(3,event)" onkeyup="validateCreate(3,event)"></td>
96 + </tr>
97 + <tr>
98 + <td id="nuPass2" align="right">Password:</td>
99 + <td><input id="apassword2" type="password" name="password2" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(4,event)" onkeyup="validateCreate(4,event)"></td>
100 + </tr>
101 + <tr id="createPanelHint" style="display:none">
102 + <td id="nuHint" align="right">Password Hint:</td>
103 + <td><input id="apasswordhint" type="text" name="apasswordhint" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(5,event)" onkeyup="validateCreate(5,event)"></td>
104 + </tr>
105 + <tr id="newAccountPass" title="Enter the account creation token">
106 + <td id="nuToken" align="right">Creation Token:</td>
107 + <td><input id="anewaccountpass" type="password" name="anewaccountpass" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(6,event)" onkeyup="validateCreate(6,event)"></td>
108 + </tr>
109 + <tr>
110 + <td colspan="2">
111 + <div style="float:right"><input id="createButton" type="submit" value="Create Account" disabled="disabled"></div>
112 + <div id="passWarning" style="padding-top:6px"></div>
113 + </td>
114 + </tr>
115 + </tbody></table>
116 + <hr><a onclick="return xgo(1,event);" href="#" style="cursor:pointer">Back to login</a>
117 + <input id="createformargs" name="urlargs" type="hidden" value="">
118 + </form>
119 + </div>
120 + <div id="resetpanel" style="display:none">
121 + <form method="post">
122 + <input type="hidden" name="action" value="resetaccount">
123 + <div id="message3">
124 + {{{message}}}
125 + </div>
126 + <div>
127 + <b>Account Reset</b>
128 + </div>
129 + <table>
130 + <tbody><tr>
131 + <td align="right" width="100">Email:</td>
132 + <td><input id="remail" type="text" name="email" maxlength="256" onchange="validateReset()" onkeyup="validateReset(event)"></td>
133 + </tr>
134 + <tr>
135 + <td colspan="2">
136 + <div style="float:right"><input id="eresetButton" type="submit" value="Reset Account" disabled="disabled"></div>
137 + <div id="passWarning" style="padding-top:6px"></div>
138 + </td>
139 + </tr>
140 + </tbody></table>
141 + <hr><a onclick="return xgo(1,event);" href="#" style="cursor:pointer">Back to login</a>
142 + <input id="resetformargs" name="urlargs" type="hidden" value="">
143 + </form>
144 + </div>
145 + <div id="tokenpanel" style="display:none">
146 + <form method="post" autocomplete="off">
147 + <input type="hidden" name="action" value="tokenlogin">
148 + <input type="hidden" name="hwstate" value="{{{hwstate}}}">
149 + <div id="message4">
150 + {{{message}}}
151 + </div>
152 + <table>
153 + <tbody><tr>
154 + <td align="right" width="100">Login token:</td>
155 + <td>
156 + <input id="tokenInput" type="text" name="token" maxlength="50" onchange="checkToken(event)" onpaste="resetCheckToken(event)" onkeyup="checkToken(event)" onkeydown="checkToken(event)">
157 + <input id="hwtokenInput" type="text" name="hwtoken" style="display:none">
158 + </td>
159 + </tr>
160 + <tr>
161 + <td colspan="2">
162 + <div style="float:right"><input id="tokenOkButton" type="submit" value="Login" disabled="disabled"></div>
163 + </td>
164 + </tr>
165 + </tbody></table>
166 + <hr><a onclick="return xgo(1,event);" href="#" style="cursor:pointer">Back to login</a>
167 + <input id="tokenformargs" name="urlargs" type="hidden" value="">
168 + </form>
169 + </div>
170 + <div id="resettokenpanel" style="display:none">
171 + <form method="post">
172 + <input type="hidden" name="action" value="resetaccount">
173 + <div id="message5">
174 + {{{message}}}
175 + </div>
176 + <table>
177 + <tbody><tr>
178 + <td align="right" width="100">Login token:</td>
179 + <td>
180 + <input id="resetTokenInput" type="text" name="token" maxlength="50" onchange="resetCheckToken(event)" onkeyup="resetCheckToken(event)" onkeydown="resetCheckToken(event)">
181 + <input id="resetHwtokenInput" type="text" name="hwtoken" style="display:none">
182 + </td>
183 + </tr>
184 + <tr>
185 + <td colspan="2">
186 + <div style="float:right"><input id="resetTokenOkButton" type="submit" value="Login" disabled="disabled"></div>
187 + </td>
188 + </tr>
189 + </tbody></table>
190 + <hr><a onclick="return xgo(1,event);" href="#" style="cursor:pointer">Back to login</a>
191 + <input id="resettokenformargs" name="urlargs" type="hidden" value="">
192 + </form>
193 + </div>
194 + <div id="resetpasswordpanel" style="display:none;position:relative">
195 + <form method="post">
196 + <input type="hidden" name="action" value="resetpassword">
197 + <div id="message6">
198 + {{{message}}}
199 + </div>
200 + <div id="rpasswordPolicyCallout" style="display:none"></div>
201 + <table>
202 + <tbody><tr>
203 + <td id="rnuPass1" width="100" align="right">Password:</td>
204 + <td><input id="rapassword1" type="password" name="rpassword1" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(3,event)" onkeyup="validatePassReset(3,event)"></td>
205 + </tr>
206 + <tr>
207 + <td id="rnuPass2" align="right">Password:</td>
208 + <td><input id="rapassword2" type="password" name="rpassword2" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(4,event)" onkeyup="validatePassReset(4,event)"></td>
209 + </tr>
210 + <tr id="resetpasswordpanelHint" style="display:none">
211 + <td id="rnuHint" align="right">Password Hint:</td>
212 + <td><input id="rapasswordhint" type="text" name="rpasswordhint" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(5,event)" onkeyup="validatePassReset(5,event)"></td>
213 + </tr>
214 + <tr>
215 + <td colspan="2">
216 + <div style="float:right"><input id="resetPassButton" type="submit" value="Reset Password" disabled="disabled"></div>
217 + <div id="rpassWarning" style="padding-top:6px"></div>
218 + </td>
219 + </tr>
220 + </tbody></table>
221 + <hr><a onclick="return xgo(1,event);" href="#" style="cursor:pointer">Back to login</a>
222 + <input id="resetpasswordformargs" name="urlargs" type="hidden" value="">
223 + </form>
224 + </div>
225 + </td>
226 + </tr>
227 + </tbody></table>
228 + <br>
229 + </div>
230 + <div id="footer">
231 + <div class="footer1">{{{footer}}}</div>
232 + <div class="footer2">
233 + {{{rootCertLink}}}
234 + &nbsp;<a href="terms">Terms &amp; Privacy</a>
235 + </div>
236 + </div>
237 +
238 + </div>
239 + <div id="dialog" style="display:none">
240 + <div id="dialogHeader">
241 + <div id="id_dialogclose" style="float:right;padding:5px;cursor:pointer" onclick="setDialogMode()"><b>X</b></div>
242 + <div id="id_dialogtitle" style="padding:5px"></div>
243 + <div style="width:100%;margin:6px"></div>
244 + </div>
245 + <div id="dialogBody">
246 + <div id="dialog1">
247 + <div id="id_dialogMessage" style=""></div>
248 + </div>
249 + <div id="dialog2" style="">
250 + <div id="id_dialogOptions"></div>
251 + </div>
252 + </div>
253 + <div id="idx_dlgButtonBar" style="">
254 + <input id="idx_dlgCancelButton" type="button" value="Annuler" style="" onclick="dialogclose(0)">
255 + <input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)">
256 + </div>
257 + </div>
258 + <script>
259 + 'use strict';
260 + var passhint = '{{{passhint}}}';
261 + var newAccountPass = parseInt('{{{newAccountPass}}}');
262 + var emailCheck = ('{{{emailcheck}}}' == 'true');
263 + var passRequirements = '{{{passRequirements}}}';
264 + var hardwareKeyChallenge = decodeURIComponent('{{{hkey}}}');
265 + if (passRequirements != '') { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); } else { passRequirements = {}; }
266 + var passRequirementsEx = ((passRequirements.min != null) || (passRequirements.max != null) || (passRequirements.upper != null) || (passRequirements.lower != null) || (passRequirements.numeric != null) || (passRequirements.nonalpha != null));
267 + var features = parseInt('{{{features}}}');
268 + var welcomeText = decodeURIComponent('{{{welcometext}}}');
269 + var currentpanel = 0;
270 + var uiMode = parseInt(getstore('uiMode', '1'));
271 + var webPageFullScreen = true;
272 + var nightMode = (getstore('_nightMode', '0') == '1');
273 + var publicKeyCredentialRequestOptions = null;
274 +
275 + // If URL arguments are provided, add them to form posts
276 + if (window.location.href.indexOf('?') > 0) {
277 + var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
278 + Q('loginformargs').value = urlargs;
279 + Q('createformargs').value = urlargs;
280 + Q('resetformargs').value = urlargs;
281 + Q('tokenformargs').value = urlargs;
282 + Q('resettokenformargs').value = urlargs;
283 + Q('resetpasswordformargs').value = urlargs;
284 + }
285 +
286 + //var webPageFullScreen = getstore('webPageFullScreen', true);
287 + //if (webPageFullScreen == 'false') { webPageFullScreen = false; }
288 + //if (webPageFullScreen == 'true') { webPageFullScreen = true; }
289 + //toggleFullScreen();
290 +
291 + function startup() {
292 + if ((features & 32) == 0) {
293 + // Guard against other site's top frames (web bugs).
294 + var loc = null;
295 + try { loc = top.location.toString().toLowerCase(); } catch (e) { }
296 + if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
297 + }
298 +
299 + if (features & 0x200000) { // Email is username
300 + QH('loginusername', "Email:");
301 + QH('resetAccountSpan', "Forgot password?");
302 + QV('nuUserRow', false);
303 + }
304 +
305 + if (nightMode) { QC('body').add('night'); }
306 +
307 + QV('createPanelHint', passRequirements.hint === true);
308 + QV('resetpasswordpanelHint', passRequirements.hint === true);
309 +
310 + // Display the welcome text
311 + if (welcomeText) { QH('welcomeText', welcomeText); }
312 + QV('welcomeText', true);
313 +
314 + window.onresize = center;
315 + center();
316 +
317 + validateLogin();
318 + validateCreate();
319 + if ('{{loginmode}}' != '') { go(parseInt('{{loginmode}}')); } else { go(1); }
320 + QV('newAccountDiv', ('{{{newAccount}}}' === '1') || ('{{{newAccount}}}' === 'true')); // If new accounts are not allowed, don't display the new account link.
321 + if ((passhint != null) && (passhint.length > 0)) { QV('showPassHintLink', true); }
322 + QV('newAccountPass', (newAccountPass == 1));
323 + QV('resetAccountDiv', (emailCheck == true));
324 + QV('hrAccountDiv', (emailCheck == true) || (newAccountPass == 1));
325 +
326 + if ('{{loginmode}}' == '4') {
327 + try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
328 + if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
329 + hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer;
330 +
331 + publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
332 + for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
333 + publicKeyCredentialRequestOptions.allowCredentials.push(
334 + { id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
335 + );
336 + }
337 +
338 + // New WebAuthn hardware keys
339 + navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
340 + function (rawAssertion) {
341 + var assertion = {
342 + id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
343 + clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
344 + userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
345 + signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
346 + authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
347 + };
348 + Q('hwtokenInput').value = JSON.stringify(assertion);
349 + QE('tokenOkButton', true);
350 + Q('tokenOkButton').click();
351 + },
352 + function (error) {
353 + console.log('credentials-get error', error);
354 + }
355 + );
356 + }
357 + }
358 +
359 + if ('{{loginmode}}' == '5') {
360 + try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
361 + if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
362 + hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer;
363 +
364 + publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
365 + for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
366 + publicKeyCredentialRequestOptions.allowCredentials.push(
367 + { id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
368 + );
369 + }
370 +
371 + // New WebAuthn hardware keys
372 + navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
373 + function (rawAssertion) {
374 + var assertion = {
375 + id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
376 + clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
377 + userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
378 + signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
379 + authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
380 + };
381 + Q('resetHwtokenInput').value = JSON.stringify(assertion);
382 + QE('resetTokenOkButton', true);
383 + Q('resetTokenOkButton').click();
384 + },
385 + function (error) { console.log('credentials-get error', error); }
386 + );
387 + }
388 + }
389 +
390 + // Setup the user interface in the right mode
391 + userInterfaceSelectMenu();
392 + }
393 +
394 + function showPassHint(e) {
395 + messagebox("Password Hint", passhint);
396 + haltEvent(e);
397 + return false;
398 + }
399 +
400 + function xgo(x, e) {
401 + QV('message1', false);
402 + QV('message2', false);
403 + QV('message3', false);
404 + QV('message4', false);
405 + QV('message5', false);
406 + QV('message6', false);
407 + go(x);
408 + haltEvent(e);
409 + return false;
410 + }
411 +
412 + function go(x) {
413 + currentpanel = x;
414 + setDialogMode(0);
415 + QV('showPassHintLink', false);
416 + QV('loginpanel', x == 1);
417 + QV('createpanel', x == 2);
418 + QV('resetpanel', x == 3);
419 + QV('tokenpanel', x == 4);
420 + QV('resettokenpanel', x == 5);
421 + QV('resetpasswordpanel', x == 6);
422 + if (x == 1) { Q('username').focus(); }
423 + if (x == 2) { if (features & 0x200000) { Q('aemail').focus(); } else { Q('ausername').focus(); } } // Email is username
424 + if (x == 3) { Q('remail').focus(); }
425 + if (x == 4) { Q('tokenInput').focus(); }
426 + if (x == 5) { Q('resetTokenInput').focus(); }
427 + if (x == 6) { Q('rapassword1').focus(); }
428 + }
429 +
430 + function validateLogin(box, e) {
431 + var ok = ((Q('username').value.length > 0) && (Q('username').value.indexOf(' ') == -1) && (Q('password').value.length > 0));
432 + QE('loginButton', ok);
433 + setDialogMode(0);
434 + if ((e != null) && (e.keyCode == 13)) { if ((box == 1) && (Q('username').value != '')) { Q('password').focus(); } else if ((box == 2) && (Q('password').value != '')) { Q('loginButton').click(); } }
435 + if (e != null) { haltEvent(e); }
436 + }
437 +
438 + function validateCreate(box, e) {
439 + setDialogMode(0);
440 + var userok = false;
441 + if (features & 0x200000) { userok = true; } else { userok = (Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (Q('ausername').value.indexOf('"') == -1) && (Q('ausername').value.indexOf(',') == -1); }
442 + var emailok = (validateEmail(Q('aemail').value) == true);
443 + var pass1ok = (Q('apassword1').value.length > 0);
444 + var pass2ok = (Q('apassword2').value.length > 0) && (Q('apassword2').value == Q('apassword1').value);
445 + var newAccOk = (newAccountPass == 0) || (Q('anewaccountpass').value.length > 0);
446 + var ok = (userok && emailok && pass1ok && pass2ok && newAccOk);
447 +
448 + // Color the fields
449 + QS('nuUser').color = userok?'black':'#7b241c';
450 + QS('nuEmail').color = emailok?'black':'#7b241c';
451 + QS('nuPass1').color = pass1ok?'black':'#7b241c';
452 + QS('nuPass2').color = pass2ok?'black':'#7b241c';
453 + QS('nuToken').color = newAccOk?'black':'#7b241c';
454 +
455 + if (Q('apassword1').value == '') {
456 + QH('passWarning', '');
457 + QV('passwordPolicyCallout', false);
458 + } else {
459 + if (!passRequirementsEx) {
460 + // No password requirements, display password strength
461 + var passStrength = checkPasswordStrength(Q('apassword1').value);
462 + if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>' + "Mot de passe fort" + '</b><span>'); }
463 + else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>' + "Good Password" + '</b><span>'); }
464 + else { QH('passWarning', '<span style=color:red><b>' + "Mot de passe faible" + '</b><span>'); }
465 + } else {
466 + // Password requirements provided, use that
467 + var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
468 + if (passReq == false) {
469 + ok = false;
470 + QS('nuPass1').color = '#7b241c';
471 + QS('nuPass2').color = '#7b241c';
472 + QH('passWarning', '<div style=color:red;cursor:pointer onclick=showPasswordPolicy()><b>' + "Password Policy" + '</b><div>'); // This is also a link to the password policy
473 + QV('passwordPolicyCallout', true);
474 + QH('passwordPolicyCallout', passwordPolicyText(Q('apassword1').value));
475 + } else {
476 + QH('passWarning', '');
477 + QV('passwordPolicyCallout', false);
478 + }
479 + }
480 + }
481 + if ((e != null) && (e.keyCode == 13)) {
482 +
483 + if ((box == 1) && userok) { Q('aemail').focus(); }
484 + if ((box == 2) && emailok) { Q('apassword1').focus(); }
485 + if ((box == 3) && pass1ok) { Q('apassword2').focus(); }
486 + if ((box == 4) && pass2ok) { if (passRequirements.hint === true) { Q('apasswordhint').focus(); } else { box = 5; } }
487 + if (box == 5) { if (newAccountPass == 1) { Q('anewaccountpass').focus(); } else { box = 6; } }
488 + if (box == 6) { Q('createButton').click(); }
489 + }
490 + if (e != null) { haltEvent(e); }
491 + QE('createButton', ok);
492 + }
493 +
494 + function validatePassReset(box, e) {
495 + setDialogMode(0);
496 + var pass1ok = (Q('rapassword1').value.length > 0);
497 + var pass2ok = (Q('rapassword2').value.length > 0) && (Q('rapassword2').value == Q('rapassword1').value);
498 + var ok = (pass1ok && pass2ok);
499 +
500 + // Color the fields
501 + QS('rnuPass1').color = pass1ok ? 'black' : '#7b241c';
502 + QS('rnuPass2').color = pass2ok ? 'black' : '#7b241c';
503 +
504 + if (Q('rapassword1').value == '') {
505 + QH('rpassWarning', '');
506 + QV('rpasswordPolicyCallout', false);
507 + } else {
508 + if (!passRequirementsEx) {
509 + // No password requirements, display password strength
510 + var passStrength = checkPasswordStrength(Q('rapassword1').value);
511 + if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>' + "Mot de passe fort" + '</b><span>'); }
512 + else if (passStrength >= 60) { QH('rpassWarning', '<span style=color:blue><b>' + "Good Password" + '</b><span>'); }
513 + else { QH('rpassWarning', '<span style=color:red><b>' + "Mot de passe faible" + '</b><span>'); }
514 + } else {
515 + // Password requirements provided, use that
516 + var passReq = checkPasswordRequirements(Q('rapassword1').value, passRequirements);
517 + if (passReq == false) {
518 + ok = false;
519 + QS('rnuPass1').color = '#7b241c';
520 + QS('rnuPass2').color = '#7b241c';
521 + QH('rpassWarning', '<div style=color:red;cursor:pointer onclick=showPasswordPolicy()><b>' + "Password Policy" + '</b><div>'); // This is also a link to the password policy
522 + QV('rpasswordPolicyCallout', true);
523 + QH('rpasswordPolicyCallout', passwordPolicyText(Q('rapassword1').value));
524 + } else {
525 + QH('rpassWarning', '');
526 + QV('rpasswordPolicyCallout', false);
527 + }
528 + }
529 + }
530 + if ((e != null) && (e.keyCode == 13)) {
531 + if (box == 2) { Q('rapassword1').focus(); }
532 + if (box == 3) { Q('rapassword2').focus(); }
533 + if (box == 4) { Q('rapasswordhint').focus(); }
534 + if (box == 6) { Q('resetPassButton').click(); }
535 + }
536 + if (e != null) { haltEvent(e); }
537 + QE('resetPassButton', ok);
538 + }
539 +
540 + function passwordPolicyText(pass) {
541 + var policy = '<div style=text-align:left>';
542 + var counts = strCount(pass);
543 + if (passRequirements.min && ((pass == null) || (pass.length < passRequirements.min))) { policy += format("Minimum length of {0}", passRequirements.min) + '<br />'; }
544 + if (passRequirements.max && ((pass == null) || (pass.length > passRequirements.max))) { policy += format("Maximum length of {0}", passRequirements.max) + '<br />'; }
545 + if (passRequirements.upper && ((pass == null) || (counts.upper < passRequirements.upper))) { policy += format("{0} upper case", passRequirements.upper) + '<br />'; }
546 + if (passRequirements.lower && ((pass == null) || (counts.lower < passRequirements.lower))) { policy += format("{0} lower case", passRequirements.lower) + '<br />'; }
547 + if (passRequirements.numeric && ((pass == null) || (counts.numeric < passRequirements.numeric))) { policy += format("{0} numeric", passRequirements.numeric) + '<br />'; }
548 + if (passRequirements.nonalpha && ((pass == null) || (counts.nonalpha < passRequirements.nonalpha))) { policy += format("{0} non-alphanumeric", passRequirements.nonalpha) + '<br />'; }
549 + policy += '</div>';
550 + return policy;
551 + }
552 +
553 + function showPasswordPolicy() {
554 + messagebox("Password Policy", passwordPolicyText());
555 + }
556 +
557 + function validateReset(e) {
558 + setDialogMode(0);
559 + var x = validateEmail(Q('remail').value);
560 + QE('eresetButton', x);
561 + if ((e != null) && (e.keyCode == 13) && (x == true)) {
562 + Q('eresetButton').click();
563 + }
564 + if (e != null) { haltEvent(e); }
565 + }
566 +
567 + // Return a password strength score
568 + function checkPasswordStrength(password) {
569 + var r = 0, letters = {}, varCount = 0, variations = { digits: /\d/.test(password), lower: /[a-z]/.test(password), upper: /[A-Z]/.test(password), nonWords: /\W/.test(password) }
570 + if (!password) return 0;
571 + for (var i = 0; i< password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; }
572 + for (var c in variations) { varCount += (variations[c] == true) ? 1 : 0; }
573 + return parseInt(r + (varCount - 1) * 10);
574 + }
575 +
576 + // Check password requirements
577 + function checkPasswordRequirements(password, requirements) {
578 + if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
579 + if (requirements.min) { if (password.length < requirements.min) return false; }
580 + if (requirements.max) { if (password.length > requirements.max) return false; }
581 + var counts = strCount(password);
582 + if (requirements.numeric && (counts.numeric < requirements.numeric)) return false;
583 + if (requirements.lower && (counts.lower < requirements.lower)) return false;
584 + if (requirements.upper && (counts.upper < requirements.upper)) return false;
585 + if (requirements.nonalpha && (counts.nonalpha < requirements.nonalpha)) return false;
586 + return true;
587 + }
588 +
589 + function strCount(password) {
590 + var counts = { numeric: 0, lower: 0, upper: 0, nonalpha: 0 };
591 + if (typeof password != 'string') return counts;
592 + for (var i = 0; i < password.length; i++) {
593 + if (/\d/.test(password[i])) { counts.numeric++; }
594 + if (/[a-z]/.test(password[i])) { counts.lower++; }
595 + if (/[A-Z]/.test(password[i])) { counts.upper++; }
596 + if (/\W/.test(password[i])) { counts.nonalpha++; }
597 + }
598 + return counts;
599 + }
600 +
601 + function checkToken() {
602 + var t1 = Q('tokenInput').value;
603 + var t2 = t1.split(' ').join('');
604 + if (t1 != t2) { Q('tokenInput').value = t2; }
605 + QE('tokenOkButton', (Q('tokenInput').value.length == 6) || (Q('tokenInput').value.length == 8) || (Q('tokenInput').value.length == 44));
606 + }
607 +
608 + function resetCheckToken() {
609 + var t1 = Q('resetTokenInput').value;
610 + var t2 = t1.split(' ').join('');
611 + if (t1 != t2) { Q('resetTokenInput').value = t2; }
612 + QE('resetTokenOkButton', (Q('resetTokenInput').value.length == 6) || (Q('resetTokenInput').value.length == 8) || (Q('resetTokenInput').value.length == 44));
613 + }
614 +
615 + //
616 + // POPUP DIALOG
617 + //
618 +
619 + // undefined = Hidden, 1 = Generic Message
620 + var xxdialogMode;
621 + var xxdialogFunc;
622 + var xxdialogButtons;
623 + var xxdialogTag;
624 + var xxcurrentView = 0;
625 +
626 + // Display a dialog box
627 + // Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
628 + function setDialogMode(x, y, b, f, c, tag) {
629 + xxdialogMode = x;
630 + xxdialogFunc = f;
631 + xxdialogButtons = b;
632 + xxdialogTag = tag;
633 + QE('idx_dlgOkButton', true);
634 + QV('idx_dlgOkButton', b & 1);
635 + QV('idx_dlgCancelButton', b & 2);
636 + QV('id_dialogclose', (b & 2) || (b & 8));
637 + QV('idx_dlgButtonBar', b & 7);
638 + if (y) QH('id_dialogtitle', y);
639 + for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
640 + QV('dialog', x);
641 + if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
642 + }
643 +
644 + function dialogclose(x) {
645 + var f = xxdialogFunc;
646 + var b = xxdialogButtons;
647 + var t = xxdialogTag;
648 + setDialogMode();
649 + if (((b & 8) || x) && f) f(x, t);
650 + }
651 +
652 + // Toggle the web page to full screen
653 + function toggleFullScreen(toggle) {
654 + //if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
655 + if (webPageFullScreen == false) {
656 + // By adding body class, it will change a style of all ellements using CSS selector
657 + // No need for JS anymore and it will be consistent style for all the templates.
658 + QC('body').remove('fullscreen');
659 + } else {
660 + QC('body').add('fullscreen');
661 + }
662 + QV('body', true);
663 + center();
664 + }
665 +
666 + // Toggle user interface menu
667 + function showUserInterfaceSelectMenu() {
668 + Q('uiViewButton1').classList.remove('uiSelectorSel');
669 + Q('uiViewButton2').classList.remove('uiSelectorSel');
670 + Q('uiViewButton3').classList.remove('uiSelectorSel');
671 + try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
672 + QV('uiMenu', (QS('uiMenu').display == 'none'));
673 + if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
674 + }
675 +
676 + function userInterfaceSelectMenu(s) {
677 + if (s) { uiMode = s; putstore('uiMode', uiMode); }
678 + webPageFullScreen = (uiMode < 3);
679 + //webPageStackMenu = (uiMode > 1);
680 + toggleFullScreen(0);
681 + //toggleStackMenu(0);
682 + }
683 +
684 + function toggleNightMode() {
685 + nightMode = !nightMode;
686 + if (nightMode) { QC('body').add('night'); } else { QC('body').remove('night'); }
687 + putstore('_nightMode', (nightMode ? '1' : '0'));
688 + }
689 +
690 + function center() {
691 + /* Now we use CSS media to achive the same effect as deleted JS */
692 + if (webPageFullScreen == false) {
693 + QS('centralTable')['margin-top'] = '';
694 + } else {
695 + var h = ((Q('column_l').clientHeight) / 2) - 220;
696 + if (h < 0) h = 0;
697 + QS('centralTable')['margin-top'] = h + 'px';
698 + }
699 + }
700 + function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
701 + function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
702 + function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
703 + function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
704 + function haltReturn(e) { if (e.keyCode == 13) { haltEvent(e); } }
705 + function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
706 + function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
707 + function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
708 + function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
709 +
710 + </script>
711 +
712 +</body></html>
\ No newline at end of file
views/translations/message_fr.handlebars new
+40
@@ -0,0 +1,40 @@
1 +<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
2 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
3 + <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
4 + <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
5 + <meta name="apple-mobile-web-app-capable" content="yes">
6 + <meta name="format-detection" content="telephone=no">
7 + <link type="text/css" href="/styles/style.css" media="screen" rel="stylesheet" title="CSS">
8 + <title>MeshCentral - {{{title3}}}</title>
9 +</head>
10 +<body>
11 + <div id="container" style="max-height:100vh">
12 + <div id="mastheadx"></div>
13 + <div id="masthead" style="background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden">
14 + <div style="float:left;height:66px;color:#c8c8c8;padding-left:20px;padding-top:8px">
15 + <strong><font style="font-size:46px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
16 + </div>
17 + <div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:14px">
18 + <strong><font style="font-size:14px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
19 + </div>
20 + </div>
21 + <div id="page_content" style="max-height:calc(100vh-138px)">
22 + <div id="column_l">
23 + <h1>{{{title3}}}</h1>
24 + <p style="margin-left:20px">{{{message}}}</p>
25 + <br>
26 + </div>
27 + <div id="footer">
28 + <table cellpadding="0" cellspacing="10" style="width:100%">
29 + <tbody><tr>
30 + <td style="text-align:left"></td>
31 + <td style="text-align:right">
32 + <a href="terms">Terms &amp; Privacy</a>
33 + </td>
34 + </tr>
35 + </tbody></table>
36 + </div>
37 + </div>
38 + </div>
39 +
40 +</body></html>
\ No newline at end of file
views/translations/messenger_fr.handlebars new
+641
@@ -0,0 +1,641 @@
1 +<!DOCTYPE html><html style="height:100%"><head>
2 + <title>MeshMessenger</title>
3 + <meta http-equiv="X-UA-Compatible" content="IE=edge">
4 + <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
5 + <meta name="format-detection" content="telephone=no">
6 + <link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
7 + <link type="text/css" href="styles/messenger.css" media="screen" rel="stylesheet" title="CSS">
8 + <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
9 + <script type="text/javascript" src="scripts/filesaver.js"></script>
10 + </head>
11 + <body style="font-family:Arial,Helvetica,sans-serif">
12 + <div id="xtop" style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray">
13 + <div id="notifyButton" class="icon13 topButton" style="margin-right:4px;display:none" title="Enable browser notification" onclick="enableNotificationsButtonClick()"></div>
14 + <div id="fileButton" class="icon4 topButton" title="Share a file" style="display:none" onclick="fileButtonClick()"></div>
15 + <div id="camButton" class="icon2 topButton" title="Activer caméra et microphone" style="display:none" onclick="camButtonClick()"></div>
16 + <div id="micButton" class="icon6 topButton" title="Activer le microphone" style="display:none" onclick="micButtonClick()"></div>
17 + <div id="hangupButton" class="icon11 topRedButton" title="Hang up" style="display:none" onclick="hangUpButtonClick(1)"></div>
18 + <div style="display:inline-block;width:2px"></div>
19 + <div style="padding-top:9px;padding-left:6px;font-size:20px;display:inline-block"><b>MeshMessenger<span id="xtitle"></span></b></div>
20 + </div>
21 + <div id="xmiddle" style="position:absolute;left:0;right:0;top:38px;bottom:30px">
22 + <div style="position:absolute;left:0;right:0;top:0;bottom:0;overflow-y:scroll">
23 + <div id="xmsg" style="position:absolute;left:0;right:0;bottom:0;padding:5px"></div>
24 + </div>
25 + </div>
26 + <div id="xbottom" style="position:absolute;left:0;right:0;bottom:0px;height:30px;background-color:#036">
27 + <div style="position:absolute;left:5px;right:215px;bottom:4px;top:4px;background-color:aliceblue"><input id="xouttext" type="text" style="width:calc(100% - 5px)" onfocus="onUserInputFocus(1)" onblur="onUserInputFocus(0)"></div>
28 + <input type="button" id="sendButton" value="Send" style="position:absolute;right:110px;width:100px;top:4px;" onclick="xsend(event)">
29 + <input type="button" id="clearButton" value="Clear" style="position:absolute;right:5px;width:100px;top:4px;" onclick="displayClear()">
30 + </div>
31 + <div id="remoteVideo" style="position:absolute;right:24px;top:45px;width:320px;height:calc(240px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none">
32 + <div style="position:absolute;right:0;left:0;top:2.5px;text-align:center">Remote</div>
33 + <video id="remoteVideoCanvas" autoplay="" style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:black"></video>
34 + </div>
35 + <div id="localVideo" style="position:absolute;right:24px;top:320px;width:160px;height:calc(120px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none">
36 + <div style="position:absolute;right:0;left:0;top:2.5px;text-align:center">Local</div>
37 + <video id="localVideoCanvas" autoplay="" muted="" style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:black"></video>
38 + </div>
39 + <input id="uploadFileInput" type="file" multiple="" style="display:none">
40 + <script type="text/javascript" onunload="onUnLoad()">
41 + var userInputFocus = 0;
42 + var args = parseUriArgs();
43 + var socket = null; // Websocket object
44 + var state = 0; // Connection state. 0 = Disconnected, 1 = Connecting, 2 = Connected.
45 +
46 + // WebRTC sessions and data, audio and video channels
47 + var random = Math.random(); // Selected random, larger value initiates WebRTC.
48 + var webrtcSessions = { }; // WebRTC objects: 0 for data, 1 for outbound audio/video, 2 for inbound audio/video
49 + var webchannel = null; // WebRTC data channel
50 + var localStream = null;
51 + var remoteStream = null;
52 + var multiWebRtc = true; // if set to true, multiple WebRTC sessions will be setup. If false, everything uses one session.
53 + var userMediaSupport = 0;
54 + var notification = null;
55 + getUserMediaSupport(function (x) { userMediaSupport = x; })
56 + var webrtcconfiguration = '{{{webrtconfig}}}';
57 + if (webrtcconfiguration == '') { webrtcconfiguration = null; } else { try { webrtcconfiguration = JSON.parse(decodeURIComponent(webrtcconfiguration)); } catch (ex) { console.log('Invalid WebRTC config: \"' + webrtcconfiguration + '\".'); webrtcconfiguration = null; } }
58 +
59 + // File transfer state
60 + var fileUploads = [];
61 + var fileDownloads = {};
62 + var currentFileUpload = null;
63 + var currentFileDownload = null;
64 +
65 + // Set the title
66 + if (args.title) { QH('xtitle', ' - ' + args.title); document.title = document.title + ' - ' + args.title; }
67 +
68 + // Setup web notifications
69 + if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
70 +
71 + // Listen to drag & drop events
72 + document.addEventListener('dragover', haltEvent, false);
73 + document.addEventListener('dragleave', haltEvent, false);
74 + document.addEventListener('drop', fileDrop, false);
75 +
76 + document.onclick = function (e) {
77 + if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
78 + if (notification != null) { notification.close(); notification = null; }
79 + }
80 +
81 + // Trap document key up events
82 + document.onkeyup = function ondockeypress(e) {
83 + if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
84 + if (notification != null) { notification.close(); notification = null; }
85 + if (state == 2) {
86 + if ((e.keyCode == 8) && (userInputFocus == 0)) {
87 + // Backspace
88 + var outtext = Q('xouttext').value;
89 + if (outtext.length > 0) { Q('xouttext').value = outtext.substring(0, outtext.length - 1); }
90 + }
91 + }
92 + if (userInputFocus == 0) { haltEvent(e); return false; }
93 + }
94 +
95 + // Trap document key presses
96 + document.onkeypress = function ondockeypress(e) {
97 + if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
98 + if (notification != null) { notification.close(); notification = null; }
99 + if (state == 2) {
100 + if (e.keyCode == 13) {
101 + // Return
102 + xsend(e);
103 + } else {
104 + // Any other key
105 + if ((userInputFocus == 0) && (e.key.length == 1)) { Q('xouttext').value = Q('xouttext').value + e.key; }
106 + }
107 + }
108 + if (userInputFocus == 0) { haltEvent(e); return false; }
109 + }
110 +
111 + function onUserInputFocus(x) { userInputFocus = x; }
112 + function displayClear() { QH('xmsg', ''); cancelAllFileTransfers(); fileUploads = [], fileDownloads = {}; }
113 +
114 + // Polyfill FileReader if needed
115 + if (!FileReader.prototype.readAsBinaryString) {
116 + FileReader.prototype.readAsBinaryString = function (fileData) {
117 + var binary = '', self = this, reader = new FileReader();
118 + reader.onload = function (e) {
119 + var bytes = new Uint8Array(reader.result);
120 + for (var i = 0; i < bytes.byteLength; i++) { binary += String.fromCharCode(bytes[i]); }
121 + self.onload({ target: { result: binary } });
122 + }
123 + reader.readAsArrayBuffer(fileData);
124 + }
125 + }
126 +
127 + // Detect if microphone & camera are present
128 + // 0 = nomedia, 1 = miconly, 2 = mic&cam
129 + function getUserMediaSupport(func) {
130 + try {
131 + navigator.mediaDevices.enumerateDevices().then(function (devices) {
132 + try {
133 + var mic = 0, cam = 0;
134 + devices.forEach(function (device) {
135 + if (device.kind === 'audioinput') { mic = 1; }
136 + if (device.kind === 'videoinput') { cam = 1; }
137 + });
138 + if (mic == 0) { func(0); }
139 + func(mic + cam);
140 + } catch (ex) { }
141 + })
142 + } catch (ex) { }
143 + }
144 +
145 + // Display a control message
146 + function displayControl(msg) {
147 + QA('xmsg', '<div style="clear:both"><div style="color:gray;float:left;margin-bottom:2px">' + msg + '</div><div></div></div>');
148 + Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
149 + }
150 +
151 + function displayLocalVideo(active) { QV('localVideo', active); adjustVideoWindows(); }
152 + function displayRemoteVideo(active) { QV('remoteVideo', active); adjustVideoWindows(); }
153 + function adjustVideoWindows() {
154 + //var lv = (QS('localVideo')['display'] != 'none');
155 + var rv = (QS('remoteVideo')['display'] != 'none');
156 + QS('localVideo')['top'] = rv ? '320px' : '45px';
157 + }
158 +
159 + // Display a message from the remote user
160 + function displayRemote(msg) {
161 + QA('xmsg', '<div style="clear:both"><div class="remoteBubble">' + msg + '</div><div></div></div>');
162 + Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
163 +
164 + // If web notifications are granted, use it.
165 + if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
166 + if (Notification && (Notification.permission == 'granted')) {
167 + if (notification != null) { notification.close(); notification = null; }
168 + if (args.title) {
169 + notification = new Notification("MeshMessenger" + ' - ' + args.title, { body: msg });
170 + } else {
171 + notification = new Notification("MeshMessenger", { body: msg });
172 + }
173 + }
174 + }
175 +
176 + // Display and send a message from the local user
177 + function xsend(event) {
178 + if (notification != null) { notification.close(); notification = null; }
179 + if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
180 + var outtext = Q('xouttext').value;
181 + if (outtext.length > 0) {
182 + Q('xouttext').value = '';
183 + QA('xmsg', '<div style="clear:both"><div class="localBubble">' + outtext + '</div><div></div></div>');
184 + Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
185 + send({ action: 'chat', msg: outtext });
186 + }
187 + }
188 +
189 + function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
190 + function parseUriArgs() { var name, r = {}, parsedUri = window.document.location.href.split(/[\?&|\=]/); parsedUri.splice(0, 1); for (x in parsedUri) { switch (x % 2) { case 0: { name = decodeURIComponent(parsedUri[x]); break; } case 1: { r[name] = decodeURIComponent(parsedUri[x]); var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } break; } default: { break; } } } return r; }
191 +
192 + // Update user controls
193 + function updateControls() {
194 + QE('sendButton', state == 2);
195 + QE('clearButton', state == 2);
196 + QE('xouttext', state == 2);
197 + QV('fileButton', state == 2);
198 + QV('camButton', webchannel && webchannel.ok && !localStream && (userMediaSupport == 2));
199 + QV('micButton', webchannel && webchannel.ok && !localStream && (userMediaSupport > 0));
200 + QV('hangupButton', webchannel && webchannel.ok && localStream);
201 + }
202 +
203 + // This is the WebRTC setup
204 + function startWebRTC(id, startDataChannel) {
205 + if ((webrtcSessions[0] != null) && (multiWebRtc == false)) { return webrtcSessions[0]; };
206 +
207 + // Setup the WebRTC object
208 + var webrtc = null;
209 + if (typeof RTCPeerConnection !== 'undefined') { webrtc = new RTCPeerConnection(webrtcconfiguration); }
210 + else if (typeof webkitRTCPeerConnection !== 'undefined') { webrtc = new webkitRTCPeerConnection(webrtcconfiguration); }
211 + if (webrtc == null) return null; // No WebRTC support.
212 +
213 + webrtc.id = id;
214 + webrtc.onicecandidate = function (e) { try { if (e.candidate != null) { sendws({ action: 'webRtcIce', ice: e.candidate, id: this.id }); } } catch (ex) { } }
215 + webrtc.oniceconnectionstatechange = function () { if (webrtc && webrtc.iceConnectionState == 'failed') { webrtc.close(); if (webrtcSessions[webrtc.id]) { delete webrtcSessions[webrtc.id]; } } }
216 + webrtc.ondatachannel = function (ev) {
217 + //console.log('ondatachannel');
218 + webchannel = ev.channel;
219 + webchannel.onmessage = function (event) { processMessage(event.data, 2); };
220 + webchannel.onopen = function () { webchannel.ok = true; updateControls(); sendws({ action: 'rtcSwitch', v: 0 }); };
221 + webchannel.onclose = function (event) { if (webchannel && webchannel.ok) { disconnect(); } else { hangUpButtonClick(0); } }
222 + }
223 + webrtc.onnegotiationneeded = function (event) {
224 + if (webrtc.holdTimer != null) return;
225 + webrtc.holdTimer = setTimeout(function () { // This time is needed to keep Chrome from being to excited. Wait until we add all tracks before kicking this off.
226 + //console.log('onnegotiationneeded', id);
227 + webrtc.holdTimer = null;
228 + webrtc.createOffer(function (offer) { /*console.log('offer', offer.sdp.length);*/ webrtc.setLocalDescription(offer, function () { sendws({ action: 'webRtcSdp', sdp: offer, id: id }); }, function () { hangUpButtonClick(id); }); }, function () { hangUpButtonClick(id); });
229 + }, 20);
230 + }
231 + webrtc.ontrack = function (event) {
232 + //console.log('ontrack', id);
233 + var video = Q('remoteVideoCanvas');
234 + video.srcObject = remoteStream = event.streams[0];
235 + video.onloadedmetadata = function (e) { video.play(); };
236 + displayRemoteVideo(true);
237 + }
238 + //webrtc.onremovetrack = function (event) { console.log('onremovetrack'); }
239 + //webrtc.onicegatheringstatechange = function (event) { console.log('onicegatheringstatechange', event); }
240 + //webrtc.onsignalingstatechange = function (event) { console.log('onsignalingstatechange', event); }
241 +
242 + // Initiate the WebRTC offer or handle the offer from the peer.
243 + if (startDataChannel == true) {
244 + webchannel = webrtc.createDataChannel('DataChannel', {}); // { ordered: false, maxRetransmits: 2 }
245 + webchannel.onmessage = function (event) { processMessage(event.data, 2); };
246 + webchannel.onopen = function () { webchannel.ok = true; updateControls(); sendws({ action: 'rtcSwitch', v: 0 }); };
247 + webchannel.onclose = function (event) { if (webchannel && webchannel.ok) { disconnect(); } else { hangUpButtonClick(0); } }
248 + }
249 +
250 + webrtcSessions[id] = webrtc;
251 + return webrtc;
252 + }
253 +
254 + function webRtcHandleOffer(id, description) {
255 + //console.log('webRtcHandleOffer', description.sdp.length);
256 + var webrtc = webrtcSessions[id];
257 + if (webrtc) {
258 + webrtc.setRemoteDescription(new RTCSessionDescription(description), function () {
259 + if (description.type == 'offer') {
260 + webrtc.createAnswer(function (answer) {
261 + webrtc.setLocalDescription(answer, function (a, b) {
262 + try { sendws({ action: 'webRtcSdp', sdp: answer, id: id }); } catch (ex) { }
263 + }, function () { hangUpButtonClick(id); });
264 + }, function () { hangUpButtonClick(id); });
265 + }
266 + }, function () { hangUpButtonClick(id); });
267 + }
268 + }
269 +
270 + // Indicate to peer that data traffic will no longer be sent over websocket and start holding traffic.
271 + function performWebRtcSwitch() {
272 + if (webchannel && webchannel.ok) { sendws({ action: 'rtcSwitch', v: 1 }); webchannel.xoutBuffer = []; }
273 + }
274 +
275 + // Disconnect everything
276 + function disconnect() {
277 + if (state > 0) { displayControl("Connection closed."); }
278 + if (state > 1) { setTimeout(start, 500); }
279 + cancelAllFileTransfers();
280 + hangUpButtonClick(0, true); // Data channel
281 + hangUpButtonClick(1, true); // Local audio/video
282 + hangUpButtonClick(2, true); // Remote audio/video
283 + if (socket != null) { socket.close(); socket = null; }
284 + updateControls();
285 + state = 0;
286 + }
287 +
288 + // Send data over the current transport (WebRTC first)
289 + function send(data) {
290 + if (state != 2) return; // If not in connected state, ignore this.
291 + if (typeof data == 'object') { data = JSON.stringify(data); } // If this is an object, convert it to a string.
292 + if (webchannel && webchannel.ok) { if (webchannel.xoutBuffer != null) { webchannel.xoutBuffer.push(data); } else { webchannel.send(data); } } // If WebRTC channel is possible, use it or hold until we can use it.
293 + else { if (socket != null) { try { socket.send(data); } catch (ex) { } } } // If a websocket channel is present, use that.
294 + }
295 +
296 + // Send data over the websocket transport (WebSocket only)
297 + function sendws(data) {
298 + if (state != 2) return;
299 + //console.log('SEND', data);
300 + if (typeof data == 'object') { data = JSON.stringify(data); }
301 + if (socket != null) { socket.send(data); }
302 + }
303 +
304 + // WebRTC id switcher (0 -> 0, 1 -> 2, 2 -> 1)
305 + function webRtcIdSwitch(id) { if (id == 0) { return 0; } return 3 - id; }
306 +
307 + // Process incoming messages
308 + function processMessage(data, transport) {
309 + if (typeof data == 'string') {
310 + try { data = JSON.parse(data); } catch (ex) { console.log('Unable to parse', data); return; }
311 + //console.log('RECV', data);
312 + switch (data.action) {
313 + case 'chat': { displayRemote(data.msg); break; } // Incoming chat message.
314 + case 'random': { if (random > data.random) { startWebRTC(0, true); } break; } // If we have a larger random value, we start WebRTC.
315 + case 'webRtcSdp': { if (!webrtcSessions[webRtcIdSwitch(data.id)]) { startWebRTC(webRtcIdSwitch(data.id), false); } webRtcHandleOffer(webRtcIdSwitch(data.id), data.sdp); break; } // Remote WebRTC offer or answer.
316 + case 'webRtcIce': { var webrtc = webrtcSessions[webRtcIdSwitch(data.id)]; if (webrtc) { try { webrtc.addIceCandidate(new RTCIceCandidate(data.ice)); } catch (ex) { } } break; } // Remote ICE candidate
317 + case 'videoStop': { hangUpButtonClick(webRtcIdSwitch(data.id), true); break; }
318 + case 'rtcSwitch': { // WebRTC switch over commands.
319 + switch (data.v) {
320 + case 0: { performWebRtcSwitch(); break; } // Other side is ready for switch over to WebRTC
321 + case 1: { sendws({ action: 'rtcSwitch', v: 2 }); break; } // Other side no longer sending data on websocket, confirm we got the end marker
322 + case 2: { for (var i in webchannel.xoutBuffer) { webchannel.send(webchannel.xoutBuffer[i]); } delete webchannel.xoutBuffer; break; } // Send any pending data over WebRTC and start using WebRTC with all traffic
323 + default: { console.log('Unknown rtcSwitch value: ' + data.action); break; } //
324 + }
325 + break;
326 + }
327 + case 'file': { startFileDownload(data); break; }
328 + case 'fileUploadCancel': { cancelFileTransfer(data.id); break; }
329 + case 'fileUploadStart': {
330 + if (fileDownloads[data.id]) {
331 + currentFileDownload = fileDownloads[data.id];
332 + currentFileDownload.data = '';
333 + changeFileInfo(data.id, 2, 0);
334 + continueFileDownload(data);
335 + send({ action: 'fileUploadAck', id: data.id });
336 + } break;
337 + }
338 + case 'fileUploadEnd': {
339 + if (currentFileDownload && (currentFileDownload.id == data.id)) {
340 + changeFileInfo(data.id, 3, 200);
341 + currentFileDownload.done = 1;
342 + currentFileDownload = null;
343 + send({ action: 'fileUploadAck', id: data.id });
344 + }
345 + currentFileDownload = null;
346 + break;
347 + }
348 + case 'fileUploadAck': {
349 + continueFileUpload();
350 + break;
351 + }
352 + case 'fileData': {
353 + if (currentFileDownload && (currentFileDownload.id == data.id)) {
354 + currentFileDownload.data += data.data;
355 + changeFileInfo(data.id, 2, (currentFileDownload.data.length * 200 / currentFileDownload.size));
356 + send({ action: 'fileUploadAck', id: data.id });
357 + }
358 + break;
359 + }
360 + default: { console.log('Unhandled object data', data); break; }
361 + }
362 + } else {
363 + console.log('Unhandled data', typeof data, data);
364 + }
365 + }
366 +
367 + // File sharing button
368 + function fileButtonClick() {
369 + var chooser = Q('uploadFileInput');
370 + if (chooser.getAttribute('eventset') != 1) {
371 + chooser.setAttribute('eventset', '1');
372 + chooser.addEventListener('change', fileSelect, false);
373 + }
374 + chooser.value = null;
375 + chooser.click();
376 + }
377 +
378 + // User selected one or more files to upload to remote user.
379 + function fileSelect() {
380 + if (state != 2) return;
381 + var x = Q('uploadFileInput');
382 + if (x.files.length > 10) {
383 + displayControl("Limit of 10 file uploads at the same time.");
384 + } else {
385 + for (var i = 0; i < x.files.length; i++) {
386 + if (x.files[i].size > 0) {
387 + var reader = new FileReader();
388 + reader.onload = function (e) { this.xfile.data = e.target.result; startFileUpload(this.xfile); };
389 + reader.xfile = x.files[i];
390 + reader.readAsBinaryString(x.files[i]);
391 + }
392 + }
393 + }
394 + }
395 +
396 + // User drag & droped one or more files to upload to remote user.
397 + function fileDrop(e) {
398 + haltEvent(e);
399 + if ((state != 2) || (e.dataTransfer == null)) return;
400 + if (e.dataTransfer.files.length > 10) {
401 + displayControl("Limit of 10 file uploads at the same time.");
402 + } else {
403 + for (var i = 0; i < e.dataTransfer.files.length; i++) {
404 + if (e.dataTransfer.files[i].size > 0) {
405 + var reader = new FileReader();
406 + reader.onload = function (e) { this.xfile.data = e.target.result; startFileUpload(this.xfile); };
407 + reader.xfile = e.dataTransfer.files[i];
408 + reader.readAsBinaryString(e.dataTransfer.files[i]);
409 + }
410 + }
411 + }
412 + }
413 +
414 + function startFileUpload(file) {
415 + if (state != 2) return;
416 + file.id = Math.random();
417 + fileUploads.push(file);
418 + QA('xmsg', '<div style="clear:both"></div><div id="FILEUP-' + file.id + '" class="localBubble" style="width:240px;cursor:pointer" onclick="cancelFileTransfer(\'' + file.id + '\')"><div id="FILEUP-ICON-' + file.id + '" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-' + file.id + '" style="height:16px;overflow:hidden;white-space:nowrap;" title="' + file.name + '">' + file.name + '</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-' + file.id + '" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>');
419 + Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
420 + send({ action: 'file', size: file.size, id: file.id, type: file.type, name: file.name });
421 + if (currentFileUpload == null) continueFileUpload();
422 + }
423 +
424 + function startFileDownload(file) {
425 + if (state != 2) return;
426 + fileDownloads[file.id] = file;
427 + QA('xmsg', '<div style="clear:both"></div><div id="FILEUP-' + file.id + '" class="remoteBubble" style="width:240px;cursor:pointer" onclick="saveFileTransfer(\'' + file.id + '\')"><div id="FILEUP-ICON-' + file.id + '" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-' + file.id + '" style="height:16px;overflow:hidden;white-space:nowrap;" title="' + file.name + '">' + file.name + '</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-' + file.id + '" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>');
428 + Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
429 + }
430 +
431 + // Change the file icon and progress
432 + function changeFileInfo(id, icon, progress, progressColor) {
433 + if (icon) {
434 + Q('FILEUP-ICON-' + id).classList.remove('fileicon');
435 + Q('FILEUP-ICON-' + id).classList.remove('fileiconx');
436 + Q('FILEUP-ICON-' + id).classList.remove('fileicontransfer');
437 + Q('FILEUP-ICON-' + id).classList.remove('fileicondone');
438 + Q('FILEUP-ICON-' + id).classList.add(['fileicon', 'fileiconx', 'fileicontransfer', 'fileicondone'][icon]);
439 + }
440 + if (progress) { QS('FILEUP-PROGRESS-' + id)['width'] = progress + 'px'; }
441 + if (progressColor) { QS('FILEUP-PROGRESS-' + id)['background-color'] = progressColor; }
442 + }
443 +
444 + // Convert a string into a blob
445 + function data2blob(data) {
446 + var bytes = new Array(data.length);
447 + for (var i = 0; i < data.length; i++) bytes[i] = data.charCodeAt(i);
448 + return new Blob([new Uint8Array(bytes)]);
449 + };
450 +
451 + function saveFileTransfer(id) {
452 + var f = fileDownloads[id];
453 + if (f && f.done == 1) { saveAs(data2blob(f.data), f.name); }
454 + }
455 +
456 + function cancelFileTransfer(id) {
457 + if ((currentFileUpload != null) && (currentFileUpload.id == id)) { currentFileUpload = null; }
458 + if ((currentFileDownload != null) && (currentFileDownload.id == id)) { currentFileDownload = null; }
459 +
460 + var found = false;
461 + if (fileDownloads[id] && (fileDownloads[id].done != 1)) {
462 + delete fileDownloads[id];
463 + found = true;
464 + } else {
465 + for (var i in fileUploads) {
466 + if (fileUploads[i].id == id) {
467 + send({ action: 'fileUploadCancel', id: id });
468 + fileUploads.splice(i, 1);
469 + found = true;
470 + break;
471 + }
472 + }
473 + }
474 + if (found) { changeFileInfo(id, 1, 200, 'gray'); } // Only cancel a file if it was in the file queue.
475 + }
476 +
477 + function cancelAllFileTransfers() {
478 + for (var i in fileDownloads) { cancelFileTransfer(fileDownloads[i].id); }
479 + for (var i in fileUploads) { cancelFileTransfer(fileUploads[i].id); }
480 + }
481 +
482 + function continueFileUpload() {
483 + if (currentFileUpload == null) {
484 + // Select the next file to upload
485 + if (fileUploads.length == 0) { return; } // Nothing to do
486 + currentFileUpload = fileUploads[0];
487 + currentFileUpload.ptr = 0;
488 +
489 + // Indicate that we are sending this file
490 + send({ action: 'fileUploadStart', size: currentFileUpload.size, id: currentFileUpload.id, type: currentFileUpload.type, name: currentFileUpload.name });
491 + } else {
492 + if (currentFileUpload.size <= currentFileUpload.ptr) {
493 + // If we are done, send the end marker
494 + send({ action: 'fileUploadEnd', size: currentFileUpload.size, id: currentFileUpload.id, type: currentFileUpload.type, name: currentFileUpload.name });
495 + changeFileInfo(currentFileUpload.id, 3, 200);
496 + fileUploads.splice(0, 1);
497 + currentFileUpload = null;
498 + continueFileUpload(); // Send the next file
499 + } else {
500 + // Send the next block
501 + var nextBlockLen = Math.min(4000, currentFileUpload.data.length - currentFileUpload.ptr);
502 + var data = currentFileUpload.data.substring(currentFileUpload.ptr, currentFileUpload.ptr + nextBlockLen);
503 + send({ action: 'fileData', id: currentFileUpload.id, data: data });
504 + currentFileUpload.ptr += nextBlockLen;
505 + changeFileInfo(currentFileUpload.id, 0, (currentFileUpload.ptr * 200 / currentFileUpload.size));
506 + }
507 + }
508 + }
509 +
510 + function continueFileDownload(msg) {
511 + send({ action: 'fileUploadAck', id: msg.id });
512 + }
513 +
514 + // Toggle notification
515 + function enableNotificationsButtonClick() {
516 + if (Notification) { Notification.requestPermission().then(function (permission) { QV('notifyButton', permission != 'granted'); }); }
517 + return false;
518 + }
519 +
520 + // Camera button
521 + function camButtonClick() {
522 + if (localStream == null) { startLocalStream({ video: true, audio: true }); }
523 + }
524 +
525 + // Microphone
526 + function micButtonClick() {
527 + if (localStream == null) { startLocalStream({ video: false, audio: true }); }
528 + }
529 +
530 + function hangUpButtonClick(id, fromRemote) {
531 + //console.log('hangUpButtonClick', id);
532 + var localVideo = Q('localVideoCanvas');
533 + var remoteVideo = Q('remoteVideoCanvas');
534 + var webrtc = webrtcSessions[(multiWebRtc == true)? id : 0];
535 +
536 + if ((id == 0) && (webchannel != null)) { try { webchannel.close(); } catch (e) { } webchannel = null; }
537 +
538 + if (webrtc) {
539 + if ((multiWebRtc == true) || (id == 0)) {
540 + webrtc.ontrack = null;
541 + webrtc.onremovetrack = null;
542 + webrtc.onremovestream = null;
543 + webrtc.onnicecandidate = null;
544 + webrtc.oniceconnectionstatechange = null;
545 + webrtc.onsignalingstatechange = null;
546 + webrtc.onicegatheringstatechange = null;
547 + webrtc.onnotificationneeded = null;
548 + }
549 +
550 + if ((id == 1) && localStream) { var tracks = localStream.getTracks(); for (var i in tracks) { tracks[i].stop(); } localStream = null; }
551 + if ((id == 2) && remoteStream) { var tracks = remoteStream.getTracks(); for (var i in tracks) { tracks[i].stop(); } remoteStream = null; }
552 +
553 + if ((multiWebRtc == true) || (id == 0)) {
554 + webrtc.close();
555 + delete webrtcSessions[id];
556 + }
557 + }
558 +
559 + if (id == 1) {
560 + localVideo.removeAttribute('src');
561 + localVideo.removeAttribute('srcObject');
562 + if (localStream != null) { localStream = null; }
563 + displayLocalVideo(false);
564 + } else if (id == 2) {
565 + remoteVideo.removeAttribute('src');
566 + remoteVideo.removeAttribute('srcObject');
567 + displayRemoteVideo(false);
568 + }
569 +
570 + if (fromRemote != true) { send({ action: 'videoStop', id: id }); }
571 + updateControls();
572 + }
573 +
574 + // Setup local audio/video
575 + function startLocalStream(constraints) {
576 + var channel = (multiWebRtc == true) ? 1 : 0;
577 + if (localStream != null) return;
578 + if ((multiWebRtc == true) && (webrtcSessions[1] != null)) return;
579 + if (navigator.mediaDevices.getUserMedia) {
580 + localStream = 1;
581 + updateControls();
582 + navigator.mediaDevices.getUserMedia(constraints)
583 + .then(function (stream) {
584 + localStream = stream;
585 + var tracks = localStream.getTracks();
586 + var webrtc = startWebRTC(channel);
587 + if (constraints.video == true) {
588 + var video = Q('localVideoCanvas');
589 + video.srcObject = stream;
590 + video.onloadedmetadata = function (e) { video.play(); };
591 + displayLocalVideo(true);
592 + }
593 + for (var i in tracks) { webrtc.addTrack(tracks[i], localStream); }
594 + }, function (err) {
595 + displayControl(err.message + '.');
596 + hangUpButtonClick(1);
597 + });
598 + }
599 + }
600 +
601 + // This is the main start
602 + function start() {
603 + // Get started
604 + updateControls();
605 + if ((typeof args.id == 'string') && (args.id.length > 0)) {
606 + var url = window.location.protocol.replace('http', 'ws') + '//' + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + '/meshrelay.ashx?id=' + args.id;
607 + if ((args.auth != null) && (args.auth != '')) { url += '&auth=' + args.auth; }
608 + socket = new WebSocket(url);
609 + socket.onopen = function () { state = 1; displayControl("Waiting for other user..."); }
610 + socket.onerror = function (e) { /*console.error(e);*/ }
611 + socket.onclose = function () { disconnect(); }
612 + socket.onmessage = function (msg) {
613 + if ((state < 2) && (typeof msg.data == 'string') && ((msg.data == 'c') || (msg.data == 'cr'))) {
614 + hangUpButtonClick(0, true);
615 + hangUpButtonClick(1, true);
616 + hangUpButtonClick(2, true);
617 + displayControl("Connected.");
618 + state = 2;
619 + updateControls();
620 + sendws({ action: 'random', random: random }); // Send a random number. Higher number starts the WebRTC session.
621 + return;
622 + }
623 + if (state == 2) { processMessage(msg.data, 1); }
624 + }
625 + } else {
626 + displayControl("Error: No connection key specified.");
627 + }
628 + }
629 +
630 + start();
631 +
632 + function onUnLoad() {
633 + for (var i = 0; i < 3; i++) { if (webrtcSessions[i]) { webrtcSessions[i].close(); delete webrtcSessions[i]; } }
634 + if (webchannel != null) { try { webchannel.close(); } catch (e) { } webchannel = null; }
635 + if (socket != null) { try { socket.close(); } catch (e) { } socket = null; }
636 + }
637 +
638 + </script>
639 +
640 +
641 +</body></html>
\ No newline at end of file
webserver.js
+75 -23
@@ -84,6 +84,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
84 obj.dnsDomains = {};
85 obj.relaySessionCount = 0;
86 obj.relaySessionErrorCount = 0;
87 + obj.renderPages = null;
88
89 // Mesh Rights
90 const MESHRIGHT_EDITMESH = 1;
@@ -174,6 +175,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
175 obj.crypto.randomBytes(16, function (err, buf) { obj.httpAuthRealm = buf.toString('hex'); });
176 obj.crypto.randomBytes(48, function (err, buf) { obj.relayRandom = buf; });
177
178 + // Get non-english pages
179 + getRenderList();
180 +
181 // Setup DNS domain TLS SNI credentials
182 {
183 var dnscount = 0;
@@ -1069,28 +1073,28 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1073 var idsplit = cookie.u.split('/');
1074 if ((idsplit.length != 2) || (idsplit[0] != domain.id)) {
1075 parent.debug('web', 'handleCheckMailRequest: Invalid domain.');
1072 - res.render(getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'ERROR: Invalid domain. <a href="' + domain.url + '">Go to login page</a>.' });
1076 + render(req, res, getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'ERROR: Invalid domain. <a href="' + domain.url + '">Go to login page</a>.' });
1077 } else {
1078 obj.db.Get('user/' + cookie.u.toLowerCase(), function (err, docs) {
1079 if (docs.length == 0) {
1080 parent.debug('web', 'handleCheckMailRequest: Invalid username.');
1077 - res.render(getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'ERROR: Invalid username \"' + EscapeHtml(idsplit[1]) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
1081 + render(req, res, getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'ERROR: Invalid username \"' + EscapeHtml(idsplit[1]) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
1082 } else {
1083 var user = docs[0];
1084 if (user.email != cookie.e) {
1085 parent.debug('web', 'handleCheckMailRequest: Invalid e-mail.');
1082 - res.render(getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'ERROR: Invalid e-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
1086 + render(req, res, getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'ERROR: Invalid e-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
1087 } else {
1088 if (cookie.a == 1) {
1089 // Account email verification
1090 if (user.emailVerified == true) {
1091 parent.debug('web', 'handleCheckMailRequest: email already verified.');
1088 - res.render(getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'E-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\" already verified. <a href="' + domain.url + '">Go to login page</a>.' });
1092 + render(req, res, getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'E-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\" already verified. <a href="' + domain.url + '">Go to login page</a>.' });
1093 } else {
1094 obj.db.GetUserWithVerifiedEmail(domain.id, user.email, function (err, docs) {
1095 if (docs.length > 0) {
1096 parent.debug('web', 'handleCheckMailRequest: email already in use.');
1093 - res.render(getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'E-mail \"' + EscapeHtml(user.email) + '\" already in use on a different account. Change the email address and try again. <a href="' + domain.url + '">Go to login page</a>.' });
1097 + render(req, res, getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'E-mail \"' + EscapeHtml(user.email) + '\" already in use on a different account. Change the email address and try again. <a href="' + domain.url + '">Go to login page</a>.' });
1098 } else {
1099 parent.debug('web', 'handleCheckMailRequest: email verification success.');
1100
@@ -1105,7 +1109,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1109 obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
1110
1111 // Send the confirmation page
1108 - res.render(getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'Verified email <b>' + EscapeHtml(user.email) + '</b> for user account <b>' + EscapeHtml(user.name) + '</b>. <a href="' + domain.url + '">Go to login page</a>.' });
1112 + render(req, res, getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'Verified email <b>' + EscapeHtml(user.email) + '</b> for user account <b>' + EscapeHtml(user.name) + '</b>. <a href="' + domain.url + '">Go to login page</a>.' });
1113
1114 // Send a notification
1115 obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:<br /><b>' + EscapeHtml(user.email) + '</b>.', nolog: 1 });
@@ -1116,7 +1120,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1120 // Account reset
1121 if (user.emailVerified != true) {
1122 parent.debug('web', 'handleCheckMailRequest: email not verified.');
1119 - res.render(getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'E-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\" not verified. <a href="' + domain.url + '">Go to login page</a>.' });
1123 + render(req, res, getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'E-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\" not verified. <a href="' + domain.url + '">Go to login page</a>.' });
1124 } else {
1125 // Set a temporary password
1126 obj.crypto.randomBytes(16, function (err, buf) {
@@ -1141,20 +1145,20 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1145 obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
1146
1147 // Send the new password
1144 - res.render(getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: '<div>Password for account <b>' + EscapeHtml(user.name) + '</b> has been reset to:</div><div style=padding:14px;font-size:18px><b>' + EscapeHtml(newpass) + '</b></div>Login and go to the \"My Account\" tab to update your password. <a href="' + domain.url + '">Go to login page</a>.' });
1148 + render(req, res, getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: '<div>Password for account <b>' + EscapeHtml(user.name) + '</b> has been reset to:</div><div style=padding:14px;font-size:18px><b>' + EscapeHtml(newpass) + '</b></div>Login and go to the \"My Account\" tab to update your password. <a href="' + domain.url + '">Go to login page</a>.' });
1149 parent.debug('web', 'handleCheckMailRequest: send temporary password.');
1150 }, 0);
1151 });
1152 }
1153 } else {
1150 - res.render(getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'ERROR: Invalid account check. <a href="' + domain.url + '">Go to login page</a>.' });
1154 + render(req, res, getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'ERROR: Invalid account check. <a href="' + domain.url + '">Go to login page</a>.' });
1155 }
1156 }
1157 }
1158 });
1159 }
1160 } else {
1157 - res.render(getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'ERROR: Invalid account check, verification url is only valid for 30 minutes. <a href="' + domain.url + '">Go to login page</a>.' });
1161 + render(req, res, getRenderPage('message', req), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'ERROR: Invalid account check, verification url is only valid for 30 minutes. <a href="' + domain.url + '">Go to login page</a>.' });
1162 }
1163 }
1164 }
@@ -1176,7 +1180,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1180 var installflags = cookie.f;
1181 if (typeof installflags != 'number') { installflags = 0; }
1182 parent.debug('web', 'handleAgentInviteRequest using cookie.');
1179 - res.render(getRenderPage('agentinvite', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, meshid: mesh._id.split('/')[2], serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: ((args.notls == true) ? '0' : '1'), servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name), installflags: installflags });
1183 + render(req, res, getRenderPage('agentinvite', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, meshid: mesh._id.split('/')[2], serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: ((args.notls == true) ? '0' : '1'), servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name), installflags: installflags });
1184 } else if (req.query.m != null) {
1185 // The MeshId is specified in the query string, use that
1186 var mesh = obj.meshes['mesh/' + domain.id + '/' + req.query.m.toLowerCase()];
@@ -1185,7 +1189,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1189 if (req.query.f) { installflags = parseInt(req.query.f); }
1190 if (typeof installflags != 'number') { installflags = 0; }
1191 parent.debug('web', 'handleAgentInviteRequest using meshid.');
1188 - res.render(getRenderPage('agentinvite', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, meshid: mesh._id.split('/')[2], serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: ((args.notls == true) ? '0' : '1'), servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name), installflags: installflags });
1192 + render(req, res, getRenderPage('agentinvite', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, meshid: mesh._id.split('/')[2], serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: ((args.notls == true) ? '0' : '1'), servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name), installflags: installflags });
1193 }
1194 }
1195
@@ -1523,7 +1527,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1527 parent.debug('web', 'handleRootRequestEx: success.');
1528 obj.db.Get('ws' + user._id, function (err, states) {
1529 var webstate = (states.length == 1) ? states[0].state : '';
1526 - res.render(getRenderPage('default', req), { authCookie: authCookie, authRelayCookie: authRelayCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate), pluginHandler: (parent.pluginHandler == null)?'null':parent.pluginHandler.prepExports() });
1530 + render(req, res, getRenderPage('default', req), { authCookie: authCookie, authRelayCookie: authRelayCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(domain.title2), domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate), pluginHandler: (parent.pluginHandler == null)?'null':parent.pluginHandler.prepExports() });
1531 });
1532 } else {
1533 // Send back the login application
@@ -1595,7 +1599,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1599 if (hardwareKeyChallenge) { hwstate = obj.parent.encodeCookie({ u: req.session.tokenusername, p: req.session.tokenpassword, c: req.session.u2fchallenge }, obj.parent.loginCookieEncryptionKey) }
1600
1601 // Render the login page
1598 - res.render(getRenderPage('login', req), { loginmode: loginmode, rootCertLink: getRootCertLink(), domainurl: domain.url, title: domain.title, title2: domain.title2, newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge), message: message, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext) : null, hwstate: hwstate });
1602 + render(req, res, getRenderPage('login', req), { loginmode: loginmode, rootCertLink: getRootCertLink(), domainurl: domain.url, title: domain.title, title2: domain.title2, newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge), message: message, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext) : null, hwstate: hwstate });
1603 }
1604
1605 // Handle a post request on the root
@@ -1656,9 +1660,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1660 var user = obj.users[req.session.userid];
1661 var logoutcontrol = 'Welcome ' + user.name + '.';
1662 if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1659 - res.render(getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()), logoutControl: logoutcontrol });
1663 + render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()), logoutControl: logoutcontrol });
1664 } else {
1661 - res.render(getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()) });
1665 + render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()) });
1666 }
1667 } else {
1668 // See if there is a terms.txt file in meshcentral-data
@@ -1674,9 +1678,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1678 var user = obj.users[req.session.userid];
1679 var logoutcontrol = 'Welcome ' + user.name + '.';
1680 if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1677 - res.render(getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(data), logoutControl: logoutcontrol });
1681 + render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(data), logoutControl: logoutcontrol });
1682 } else {
1679 - res.render(getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(data) });
1683 + render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, terms: encodeURIComponent(data) });
1684 }
1685 });
1686 } else {
@@ -1688,9 +1692,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1692 var user = obj.users[req.session.userid];
1693 var logoutcontrol = 'Welcome ' + user.name + '.';
1694 if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
1691 - res.render(getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, logoutControl: logoutcontrol });
1695 + render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url, logoutControl: logoutcontrol });
1696 } else {
1693 - res.render(getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url });
1697 + render(req, res, getRenderPage('terms', req), { title: domain.title, title2: domain.title2, domainurl: domain.url });
1698 }
1699 }
1700 }
@@ -1705,7 +1709,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1709 var webRtcConfig = null;
1710 if (obj.parent.config.settings && obj.parent.config.settings.webrtconfig && (typeof obj.parent.config.settings.webrtconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(obj.parent.config.settings.webrtconfig)); }
1711 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
1708 - res.render(getRenderPage('messenger', req), { webrtconfig: webRtcConfig, domainurl: domain.url });
1712 + render(req, res, getRenderPage('messenger', req), { webrtconfig: webRtcConfig, domainurl: domain.url });
1713 }
1714
1715 // Returns the server root certificate encoded in base64
@@ -1847,10 +1851,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1851 }
1852 try { res.sendFile(obj.path.resolve(__dirname, path)); } catch (e) { res.sendStatus(404); }
1853 } else {
1850 - res.render(getRenderPage('download', req), { rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, domainurl: domain.url, message: "<a href='" + req.path + "?download=1'>" + filename + "</a>, " + stat.size + " byte" + ((stat.size < 2) ? '' : 's') + "." });
1854 + render(req, res, getRenderPage('download', req), { rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, domainurl: domain.url, message: "<a href='" + req.path + "?download=1'>" + filename + "</a>, " + stat.size + " byte" + ((stat.size < 2) ? '' : 's') + "." });
1855 }
1856 } else {
1853 - res.render(getRenderPage('download', req), { rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, domainurl: domain.url, message: "Invalid file link, please check the URL again." });
1857 + render(req, res, getRenderPage('download', req), { rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, domainurl: domain.url, message: "Invalid file link, please check the URL again." });
1858 }
1859 }
1860
@@ -3860,6 +3864,54 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3864 }
3865 }
3866
3867 + // Render a page using the proper language
3868 + function render(req, res, filename, args) {
3869 + if ((obj.parent.webViewsOverridePath == null) && (obj.renderPages != null)) {
3870 + // Get a list of acceptable languages in order
3871 + var acceptLanguages = [];
3872 + if (req.query.lang != null) {
3873 + acceptLanguages.push(req.query.lang.toLowerCase());
3874 + } else {
3875 + if (req.headers['accept-language'] != null) {
3876 + var acceptLanguageSplit = req.headers['accept-language'].split(';');
3877 + for (var i in acceptLanguageSplit) {
3878 + var acceptLanguageSplitEx = acceptLanguageSplit[i].split(',');
3879 + for (var j in acceptLanguageSplitEx) { if (acceptLanguageSplitEx[j].startsWith('q=') == false) { acceptLanguages.push(acceptLanguageSplitEx[j].toLowerCase()); } }
3880 + }
3881 + }
3882 + }
3883 +
3884 + // Take a look at the options we have for this file
3885 + var fileOptions = obj.renderPages[obj.path.basename(filename)];
3886 + for (var i in acceptLanguages) {
3887 + if ((acceptLanguages[i] == 'en') || (acceptLanguages[i].startsWith('en-'))) { break; } // English requested, break out.
3888 + if (fileOptions[acceptLanguages[i]] != null) { res.render(fileOptions[acceptLanguages[i]], args); return; } // Found a match.
3889 + }
3890 + }
3891 +
3892 + // No matches found, render the default english page.
3893 + res.render(filename, args);
3894 + }
3895 +
3896 + // Get the list of pages with different languages that can be rendered
3897 + function getRenderList() {
3898 + if (obj.fs.existsSync('views/translations')) {
3899 + obj.renderPages = {};
3900 + var files = obj.fs.readdirSync('views/translations');
3901 + for (var i in files) {
3902 + var name = files[i];
3903 + if (name.endsWith('.handlebars')) {
3904 + name = name.substring(0, name.length - 11);
3905 + var xname = name.split('_');
3906 + if (xname.length == 2) {
3907 + if (obj.renderPages[xname[0]] == null) { obj.renderPages[xname[0]] = {}; }
3908 + obj.renderPages[xname[0]][xname[1]] = obj.path.join('translations', name);
3909 + }
3910 + }
3911 + }
3912 + }
3913 + }
3914 +
3915 // Return true if a mobile browser is detected.
3916 // This code comes from "http://detectmobilebrowsers.com/" and was modified, This is free and unencumbered software released into the public domain. For more information, please refer to the http://unlicense.org/
3917 function isMobileBrowser(req) {