MeshCentral/views/default.handlebars
2018-05-01 11:42:20 -07:00

5765 lines
360 KiB
Handlebars

<!DOCTYPE html>
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="format-detection" content="telephone=no" />
<link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS" />
<link type="text/css" href="styles/ol.css" media="screen" rel="stylesheet" title="CSS" />
<link type="text/css" href="styles/ol3-contextmenu.min.css" media="screen" rel="stylesheet" title="CSS" />
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
<script type="text/javascript" src="scripts/meshcentral.js"></script>
<script type="text/javascript" src="scripts/amt-0.2.0.js"></script>
<script type="text/javascript" src="scripts/amt-wsman-0.2.0.js"></script>
<script type="text/javascript" src="scripts/amt-desktop-0.0.2.js"></script>
<script type="text/javascript" src="scripts/amt-terminal-0.0.2.js"></script>
<script type="text/javascript" src="scripts/zlib.js"></script>
<script type="text/javascript" src="scripts/zlib-inflate.js"></script>
<script type="text/javascript" src="scripts/zlib-adler32.js"></script>
<script type="text/javascript" src="scripts/zlib-crc32.js"></script>
<script type="text/javascript" src="scripts/amt-redir-ws-0.1.0.js"></script>
<script type="text/javascript" src="scripts/amt-wsman-ws-0.2.0.js"></script>
<script type="text/javascript" src="scripts/agent-redir-ws-0.1.0.js"></script>
<script type="text/javascript" src="scripts/agent-desktop-0.0.2.js"></script>
<script type="text/javascript" src="scripts/filesaver.1.1.20151003.js"></script>
<script type="text/javascript" src="scripts/ol.js"></script>
<script type="text/javascript" src="scripts/ol3-contextmenu.js"></script>
<title>MeshCentral</title>
</head>
<body onload="javascript:if (typeof(startup) !== 'undefined') startup();" oncontextmenu="handleContextMenu(event)">
<!-- right click menu -->
<div id="contextMenu" class="contextMenu" style="display: none">
<div id="cxinfo" class="cmtext" onclick="cmaction(1)"><b>Information</b></div>
<div id="cxterminal" class="cmtext" onclick="cmaction(2)">Terminal</div>
<div id="cxdesktop" class="cmtext" onclick="cmaction(3)">Desktop</div>
<div id="cxfiles" class="cmtext" onclick="cmaction(4)">Files</div>
<div id="cxevents" class="cmtext" onclick="cmaction(5)">Events</div>
<div id="cxconsole" class="cmtext" onclick="cmaction(6)">Console</div>
<hr id="cxmgroupsplit" />
<div id="cxmdesktop" class="cmtext" onclick="cmaction(7)" style=display:none>Multi-Desktop</div>
</div>
<div id="meshContextMenu" class="contextMenu" style="display: none; min-width: 0px">
<div id="cxselectall" class="cmtext" onclick="cmmeshaction(1)">Select All</div>
<div id="cxselectnone" class="cmtext" onclick="cmmeshaction(2)">Select None</div>
<hr id="cxmgroupsplit2" style=display:none />
<div id="cxmmdesktop" class="cmtext" style=display:none onclick="cmmeshaction(3)">Multi-Desktop</div>
</div>
<!-- main page -->
<div id=container style=max-height:100vh;position:relative>
<div id="notifiyBox" class="notifiyBox" style="display:none"></div>
<div id=mastheadx></div>
<div id=masthead class=noselect style="background:url(images/logoback.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden;">
<div style="float:left;height:66px;color:#c8c8c8;padding-left:20px;padding-top:8px">
<strong><font style="font-size:46px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
</div>
<div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:14px">
<strong><font style="font-size:14px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
</div>
<div style="float:right">
<div id=notificationCount onclick="clickNotificationIcon()" class="unselectable" style="display:none;min-width:28px;font-size:20px;border-radius:5px;background-color:lightblue;text-align:center;margin:8px;cursor:pointer;padding:4px" title="Click to view current notifications">0</div>
</div>
<p id="logoutControl">{{{logoutControl}}}</p>
</div>
<div id=topbarmaster>
<div id=topbar class=noselect style=display:none>
<div>
<div>
<table style=width:100%;height:22px cellpadding=0 cellspacing=0 class=style1>
<tr>
<td id=MainMenuMyDevices style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(1)>My Devices</td>
<td id=MainMenuMyAccount style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(2)>My Account</td>
<td id=MainMenuMyEvents style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(3)>My Events</td>
<td id=MainMenuMyFiles style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(5)>My Files</td>
<td id=MainMenuMyUsers style=width:100px;height:24px;cursor:pointer;display:none class=style3 onclick=go(4)>My Users</td>
<td class=style3 style="text-align:right;height:24px"><span title="Toggle full width" style="cursor:pointer;opacity:0.2" onclick="toggleFullScreen(1)">&harr;</span>&nbsp;</td>
</tr>
</table>
<div id=MainSubMenuSpan style=display:none>
<table id=MainSubMenu style=width:100%;height:22px cellpadding=0 cellspacing=0 class=style1>
<tr>
<td id=MainDev style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(10)>General</td>
<td id=MainDevDesktop style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(11)>Desktop</td>
<td id=MainDevTerminal style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(12)>Terminal</td>
<td id=MainDevFiles style=width:100px;height:24px;cursor:pointer;display:none class=style3 onclick=go(13)>Files</td>
<td id=MainDevEvents style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(16)>Events</td>
<td id=MainDevAmt style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(14)>Intel&reg; AMT</td>
<td id=MainDevConsole style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(15)>Console</td>
<td class=style3 style=height:24px>&nbsp;</td>
</tr>
</table>
</div>
<div id=MeshSubMenuSpan style=display:none>
<table id=MeshSubMenu style=width:100%;height:22px cellpadding=0 cellspacing=0 class=style1>
<tr>
<td id=MeshGeneral style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(20)>General</td>
<td class=style3 style=height:24px>&nbsp;</td>
</tr>
</table>
</div>
<div id=UserSubMenuSpan style=display:none>
<table id=UserSubMenu style=width:100%;height:22px cellpadding=0 cellspacing=0 class=style1>
<tr>
<td id=UserGeneral style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(30)>General</td>
<td id=UserEvents style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(31)>Events</td>
<td class=style3 style=height:24px>&nbsp;</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div id="page_content" style="max-height:calc(100vh - 138px)">
<div id="column_l">
<div id=p0 style=display:none>
<div id=p0message style=margin:50px;text-align:center>Server disconnected, <href onclick=reload() style=cursor:pointer><u>click to reconnect</u></href>.</div>
</div>
<div id=p1 style=display:none>
<h1>My Devices</h1>
<div style=width:100%;height:24px;background-color:#d3d9d6>
<div class=h1 style=height:100%;float:left>&nbsp;</div>
<div id=devListToolbar class=style14 style=height:100%;float:left>
&nbsp;&nbsp;<input type="button" id="SelectAllButton" onclick="selectallButtonFunction();" value="Select All" />&nbsp;
<input type=button id=GroupActionButton disabled="disabled" value="Group Action" onclick=groupActionFunction() />&nbsp;
<input id=SearchInput type=text style=width:120px placeholder=Search onchange=onSearchInputChanged() onkeyup=onSearchInputChanged() autocomplete=off onfocus=onSearchFocus(1) onblur=onSearchFocus(0) />&nbsp;
<input type=checkbox id=HostnameCheckBox onclick=onHostnameCheckBox() /><span title="Show device hostnames">Hostname</span>
</div>
<div id=kvmListToolbar class=style14 style=height:100%;float:left>
&nbsp;&nbsp;<input type="button" onclick="connectAllKvmFunction()" value="Connect All" />&nbsp;
<input type="button" onclick="disconnectAllKvmFunction()" value="Disconnect All" />&nbsp;
<input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" />AutoConnect&nbsp;
<input type="button" onclick="showMultiDesktopSettings()" value="Settings" />&nbsp;
</div>
<div id=devMapToolbar class=style14 style=height:100%;float:left>
&nbsp;&nbsp;<input type=text id=mapSearchLocation placeholder="Search Location" onfocus=onMapSearchFocus(1) onblur=onMapSearchFocus(0) />
<input type=button value=Search title="Search for location" onclick=getSearchLocation() />
<input type=button id=refreshmap title="Reset map view" value=Reset style=margin-left:5px onclick=refreshMap(false,true) />
</div>
<div class="auto-style1" style="height: 100%; float: right">
<div style="height:100%;width:4px;float:right;background-color:#ffffff"></div>
<div class=h2 style="height:100%;float:right">&nbsp;</div>
<div style=float:right id=devListToolbarView>
View
<select id=viewselect onchange=onDeviceViewChange()>
<option value=1>Columns</option>
<option value=2>List</option>
<option value=3>Desktops</option>
<option id=viewselectmapoption value=4>Map</option>
</select>
</div>
<div style=float:right id=devListToolbarSort>
Sort
<select id=sortselect onchange=onSortSelectChange()>
<option>Mesh</option>
<option>Power</option>
<option>Device</option>
<option>Group</option>
</select>
&nbsp;
</div>
<div style=float:right id=devListToolbarSize>
Size
<select id=sizeselect onchange=onDeviceViewChange()>
<option value=0>Small</option>
<option value=1>Medium</option>
<option value=2>Large</option>
</select>
&nbsp;
</div>
</div>
</div>
<div id=NoMeshesPanel style=display:none>
<table style="width:100%;padding:20px">
<tr>
<td valign="top" style="width: 50px">
<img src="images/info.png" height="48" width="47" />
</td>
<td>
To get started managing devices, <a onclick=account_createMesh() style=cursor:pointer><strong>click here to create a new group of devices called a Mesh</strong></a>.
</td>
</tr>
</table>
</div>
<div id="xdevices" style="max-height:calc(100vh - 228px);overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch"></div>
<div id="xdevicesmap" style="height:500px;width:100%;overflow:hidden;position:relative">
<div id=xmapSearchResultsDlg style="position:absolute;display:none;max-height:280px;left:5px;top:5px;max-width:250px;z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666">
<div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
<div id=xmapSearchClose style=float:right;padding:5px;cursor:pointer onclick=mapCloseSearchWindow()><b>X</b></div>
<div style=padding:5px>Location Results</div>
<div style=width:100%;margin:6px></div>
</div>
<div id=xmapSearchResults style=margin:6px></div>
</div>
</div>
<div id="xmap-info-window" style="text-shadow: 0px 0px 15px #FFF"></div>
</div>
<div id=p2 style=display:none>
<h1>My Account</h1>
<div id="p2AccountActions">
<p><strong><img alt="" width=150 height=103 src=images/mainaccount.png style=margin-bottom:10px;margin-right:20px;float:right />Account actions</strong></p>
<p style="margin-left:40px">
<span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a><br /></span>
<a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a><br />
<a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><br />
<a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a><br />
</p>
</div>
<p id="p2ServerActions"><strong>Server actions</strong></p>
<p style="margin-left:40px">
<a id="p2ServerActionsBackup" href="/backup.zip" target="_blank" style="cursor:pointer">Download server backup</a><br />
<a id="p2ServerActionsRestore" onclick="server_showRestoreDlg()" style="cursor:pointer">Restore server with backup</a><br />
<a id="p2ServerActionsVersion" onclick="server_showVersionDlg()" style="cursor:pointer">Check server version</a><br />
</p>
<br style=clear:both />
<strong>Administrative Meshes</strong>
( <a onclick=account_createMesh() style=cursor:pointer><img height=12 src="images/icon-addnew.png" width=12 border=0 /> New</a> )
<br /><br />
<div id=p2meshes></div>
<div id=p2noMeshFound style=margin-left:40px;display:none>No meshes. <a onclick=account_createMesh() style=cursor:pointer><strong>Get started here!</strong></a></div>
<br style=clear:both />
</div>
<div id=p3 style=display:none>
<h1>My Events</h1>
<div style=width:100%;height:24px;background-color:#d3d9d6;margin-bottom:4px>
<div class=style7 style=width:16px;height:100%;float:left>&nbsp;</div>
<div class=h1 style=height:100%;float:left>&nbsp;</div>
<div class=style14 style=height:100%;float:left>&nbsp;&nbsp;<input id=p2deleteall type=button onclick=showDeleteAllEventsDialog() style=display:none value="Delete All..." />&nbsp;</div>
<div class="auto-style1" style="height:100%;float:right">
Show
<select id=p3limitdropdown onchange=refreshEvents()>
<option value=60>Last 60</option>
<option value=120>Last 120</option>
<option value=250>Last 250</option>
<option value=500>Last 500</option>
<option value=1000>Last 1000</option>
</select>
<div style="height:100%;width:20px;float:right;background-color:#ffffff"></div>
<div class="h2" style="height:100%;float:right;">&nbsp;</div>
</div>
</div>
<div id=p3events style="max-height:600px;overflow-y:scroll"></div>
</div>
<div id=p4 style=display:none>
<h1>My Users</h1>
<div style=width:100%;height:24px;background-color:#d3d9d6;margin-bottom:4px>
<div class=style7 style=width:16px;height:100%;float:left>&nbsp;</div>
<div class=h1 style=height:100%;float:left>&nbsp;</div>
<div class=style14 style=height:100%;float:left>&nbsp;&nbsp;<input type=button onclick=showCreateNewAccountDialog() value="New Account..." />&nbsp;</div>
<div class=auto-style1 style="height:100%;float:right">
<div style="height:100%;width:20px;float:right;background-color:#ffffff"></div>
<div class=h2 style="height:100%;float:right">&nbsp;</div>
</div>
</div>
<div id="p3users" style="max-height:600px;overflow-y:auto"></div>
</div>
<div id=p5 style=display:none>
<h1>My Files</h1>
<table id="p5toolbar" style="width: 100%" cellpadding="0" cellspacing="0">
<tr>
<td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign=bottom>
<div id="p5rightOfButtons" style="float:right;margin-top:3px"></div>
<div>
<input type=button id=p5FolderUp disabled="disabled" onclick="p5folderup();" value="Up" />&nbsp;
<input type=button id=p5SelectAllButton disabled="disabled" onclick="p5selectallfile();" value="Select All" onkeypress="return false;" onkeydown="return false;" />&nbsp;
<input type=button id=p5RenameFileButton disabled="disabled" value="Rename" onclick="p5renamefile();" onkeypress="return false;" onkeydown="return false;" />&nbsp;
<input type=button id=p5DeleteFileButton disabled="disabled" value="Delete" onclick="p5deletefile();" onkeypress="return false;" onkeydown="return false;" />&nbsp;
<input type=button id=p5NewFolderButton disabled="disabled" value="New Folder" onclick="p5createfolder();" onkeypress="return false;" onkeydown="return false;" />&nbsp;
<input type=button id=p5UploadButton disabled="disabled" value="Upload" onclick="p5uploadFile()" onkeypress="return false;" onkeydown="return false;" />&nbsp;
<input type=button id=p5CutButton disabled="disabled" value="Cut" onclick="p5copyFile(1)" onkeypress="return false" onkeydown="return false" />&nbsp;
<input type=button id=p5CopyButton disabled="disabled" value="Copy" onclick="p5copyFile(0)" onkeypress="return false" onkeydown="return false" />&nbsp;
<input type=button id=p5PasteButton disabled="disabled" value="Paste" onclick="p5pasteFile()" onkeypress="return false" onkeydown="return false" />&nbsp;
</div>
</td>
</tr>
<tr>
<td style="background-color:#E4E9E7;height:28px">
<div style=float:right>
<select id=p5sortdropdown onchange=updateFiles()>
<option value="1" selected="selected">Sort by name</option>
<option value="2">Sort by size</option>
<option value="3">Sort by date</option>
<option value="4">Descend by name</option>
<option value="5">Descend by size</option>
<option value="6">Descend by date</option>
</select>
</div>
<div>&nbsp;&nbsp;<span id="p5currentpath"></span></div>
</td>
</tr>
</table>
<div id="p5filetable" style="width:100%;height:500px;overflow:auto;-webkit-user-select:none;position:relative">
<!--
<form id=p5fileCatchAll method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame>
<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)" />
<input id=p5fileDragLink2 name="link" style="display:none" />
<input type=submit id=p5fileCatchAllSubmit style="display:none" />
</form>
-->
<div id="p5PublicShare" style="display:none;width:100%;padding:4px;overflow:auto;-webkit-user-select:none;background-color:lightsteelblue">This files is shared publically, click "link" to get public url.</div>
<div id="bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:20px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&checkmark;</b></div>
<div id="bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:20px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&#10007;</b></div>
<span id="p5files"></span>
</div>
<table id="p5toolbarBottom" style=width:100% cellpadding=0 cellspacing=0>
<tr><td class=style6 style="text-align:left;padding:3px">&nbsp;<span id="p5bottomstatus"></span></td></tr>
</table>
</div>
<div id=p10 style=display:none>
<table style="width:100%" cellpadding="0" cellspacing="0">
<tr>
<td style=width:auto valign=top>
<div id="p10title">
<h1><span id=p10deviceName></span> - General</h1>
</div>
<div id=p10html></div>
</td>
<td style=width:20px></td>
<td style=width:200px>
<a style=cursor:pointer onclick=p10showiconselector()><img id=MainComputerImage style=border-width:0px;height:200px;width:200px></a>
<div style="width:100%;text-align:center"><strong><span id=MainComputerState></span></strong></div>
</td>
</tr>
</table><br>
<div id=p10html2></div>
<div id=p10html3></div>
</div>
<div id=p11 style=display:none>
<div id="p11title">
<h1 id=p11deviceNameHeader><span id=p11deviceName></span> - Desktop</h1>
</div>
<div id="p14warning" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showFeaturesDlg()">
<div class=icon2 style="float:left;margin:7px"></div>
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel&reg; AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div>
</div>
<div id="p14warning2" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showPowerActionDlg()">
<div class=icon2 style="float:left;margin:7px"></div>
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Remote computer is not powered on, click here to issue a power command.</div>
</div>
<table cellpadding=0 cellspacing=0 style="width:100%;padding:0px;padding:0px;margin-top:0px">
<tr id=deskarea1>
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
<div style="float:right;text-align:right">
<span id="p14power"></span>&nbsp;
<div style='cursor:pointer;border:none;float:right;font-size:130%;margin-right:4px' title="Rotate Left" onclick="drotate(-1)">&olarr;</div>
<div style='cursor:pointer;border:none;float:right;font-size:130%;margin-right:4px' title="Rotate Right" onclick="drotate(1)">&orarr;</div>
<input id="deskFullBtn" type="button" title="Toggle full screen mode" onkeypress="return false" onkeydown="return false" value="Full" onclick="deskToggleFull()" style="margin-right:3px">
<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">
<input id="deskSaveBtn" type="button" title="Save a screenshot of the remote desktop" onkeypress="return false" onkeydown="return false" value="Save..." onclick=deskSaveImage() style=margin-right:3px>
<input id="deskActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() style=margin-right:3px />
<input type="button" value="Settings..." title="Edit remote desktop settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" style="margin-right:3px">
<input type="button" title="Change the power state of the remote machine" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="margin-right:3px;display:none">
</div>
<div>
<div id="idx_deskFullBtn2" onclick=deskToggleFull() style="float:left;font-size:large;cursor:pointer;display:none">&nbsp;X</div>
<input type="button" id="autoconnectbutton1" value="AutoConnect" onclick=autoConnectDesktop(event) onkeypress="return false" onkeydown="return false" style="display:none">
<span id=connectbutton1span>&nbsp;<input type=button id=connectbutton1 value="Connect" onclick=connectDesktop(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
<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>
<span id=disconnectbutton1span>&nbsp;<input type=button id=disconnectbutton1 value="Disconnect" onclick=connectDesktop(event,0) onkeypress="return false" onkeydown="return false"></span>
&nbsp;<span id="deskstatus">Disconnected</span>
</div>
</td>
</tr>
<tr id=deskarea2>
<td>
<div style=background-color:gray><div id=progressbar style=height:2px;width:0%;background-color:red></div></div>
</td>
</tr>
<tr id=deskarea3>
<td id=deskarea3x style=background:black;text-align:center;height:400px;position:relative>
<div id=DeskFocus style="color:transparent;border:3px dotted rgba(255,0,0,.2);position:absolute;border-radius:5px" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></div>
<div id=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) onmousewheel=dmousewheel(event)></canvas>
</div>
<div id=DeskTools style="position:absolute;width:400px;height:100%;background-color:gray;top:0;right:0;border-left:2px solid lightgray;display:none">
<a id=DeskToolsRefreshButton style="float:right;padding:3px;cursor:pointer" onclick="refreshDeskTools()">Refresh</a>
<div id=DeskToolsBar style="position:absolute;padding:3px;border-radius: 3px 3px 0px 0px;top:5px;left:4px;bottom:26px;background-color:lightgray;cursor:pointer">Processes</div>
<div style="position:absolute;top:26px;left:4px;right:4px;bottom:4px;background-color:lightgray;text-align:left">
<div style="border-bottom:1px solid darkgray;padding:3px"><a style=width:50px;padding-right:5px;float:left;cursor:pointer title="Sort by process id" onclick=sortProcess(0)>PID</a><a style=cursor:pointer title="Sort by name" onclick=sortProcess(1)>Name</a></div>
<div id="DeskToolsProcesses" style="overflow-y:scroll;position:absolute;top:24px;bottom:0px;width:100%"></div>
</div>
</div>
</td>
</tr>
<tr id=deskarea4>
<td style=padding-top:2px;padding-bottom:2px;background:#C0C0C0>
<div style=float:right;text-align:right>
<select id=termdisplays style=display:none onchange=deskSetDisplay(event) onclick=deskGetDisplayNumbers(event)></select>&nbsp;
<input id=DeskToastButton type=button value=Toast title="Display a notification message on the remote computer" onkeypress="return false" onkeydown="return false" onclick="deviceToastFunction()">&nbsp;
<input id=DeskToolsButton type=button value=Tools title="Toggle tools view" onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()">&nbsp;
</div>
<div>
<select style="margin-left:6px" id="deskkeys">
<option value=0>Win+Down</option>
<option value=1>Win+Up</option>
<option value=2>Win+L</option>
<option value=3>Win+M</option>
<option value=4>Shift+Win+M</option>
</select>
<input id="DeskWD" type=button value="Send" onkeypress="return false" onkeydown="return false" onclick="deskSendKeys()">
<input id="DeskCAD" style="margin-left:6px" type="button" value="Ctrl-Alt-Del" onkeypress="return false" onkeydown="return false" onclick="sendCAD()">
<span style="margin-left:6px" title="Toggle mouse and keyboard input"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false" onclick="toggleKvmControl()">Input</span>&nbsp;
</div>
</td>
</tr>
</table>
</div>
<div id=p12 style=display:none>
<div id="p12title"><h1><span id=p12deviceName></span> - Terminal</h1></div>
<div id="p12warning" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick=showFeaturesDlg()>
<div class="icon2" style="float:left;margin:7px"></div>
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel&reg; AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div>
</div>
<div id="p12warning2" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick=showPowerActionDlg()>
<div class="icon2" style="float:left;margin:7px"></div>
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Remote computer is not powered on, click here to issue a power command.</div>
</div>
<table cellpadding=0 cellspacing=0 style="width:100%;padding:0px;padding:0px;margin-top:0px">
<tr>
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
<div style="float:right;text-align:right">
<input id="termActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() style=margin-right:3px />
</div>
<div>
<input type="button" id="autoconnectbutton2" value="AutoConnect" onclick=autoConnectTerminal(event) onkeypress="return false" onkeydown="return false" style="display:none">
<span id="connectbutton2span">&nbsp;<input type="button" id="connectbutton2" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled"></span>
<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>
<span id="disconnectbutton2span">&nbsp;<input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false"></span>
&nbsp;<span id="termstatus">Disconnected</span>
</div>
</td>
</tr>
<tr>
<td>
<div style="background-color:gray"><div id="termprogressbar" style="height:2px;width:0%;background-color:red"></div></div>
</td>
</tr>
<tr>
<td style="background:black;text-align:center;height:500px;position:relative">
<pre id="Term" style="background:black;margin:0;padding:0"></pre>
</td>
</tr>
<tr>
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
<div style="float:right;text-align:right">
<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()">&nbsp;
<input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()">&nbsp;&nbsp;
<select id="specialkeylist" onkeypress="return false"></select>
<input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />&nbsp;
</div>
<div>
&nbsp;
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Backspace" onclick="termSendKey(8,'bsbutton')" />
<input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()" />
</div>
</td>
</tr>
</table>
</div>
<div id=p13 style=display:none>
<div id="p13title"><h1><span id=p13deviceName></span> - Files</h1></div>
<table id="p13toolbar" style="width: 100%" cellpadding="0" cellspacing="0">
<tr>
<td style="background-color:#C0C0C0;border-bottom:2px solid black;padding:2px">
<div style="float:right;text-align:right">
<input id="filesActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() style=margin-right:3px />
</div>
<div>
<input id=p13AutoConnect value="AutoConnect" onclick=autoConnectFiles(event) onkeypress="return false" onkeydown="return false" type="button" style="display:none">
<input id=p13Connect value="Connect" onclick=connectFiles(event) onkeypress="return false" onkeydown="return false" type="button">
<span id=p13Status>Disconnected</span>
</div>
</td>
</tr>
<tr>
<td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign=bottom>
<div id="p13rightOfButtons" style="float:right;margin-top:3px"></div>
<div>
<input type=button id=p13FolderUp disabled="disabled" onclick="p13folderup()" value="Up" />&nbsp;
<input type=button id=p13SelectAllButton disabled="disabled" onclick="p13selectallfile()" value="Select All" onkeypress="return false" onkeydown="return false" />&nbsp;
<input type=button id=p13RenameFileButton disabled="disabled" value="Rename" onclick="p13renamefile()" onkeypress="return false" onkeydown="return false" />&nbsp;
<input type=button id=p13DeleteFileButton disabled="disabled" value="Delete" onclick="p13deletefile()" onkeypress="return false" onkeydown="return false" />&nbsp;
<input type=button id=p13NewFolderButton disabled="disabled" value="New Folder" onclick="p13createfolder()" onkeypress="return false" onkeydown="return false" />&nbsp;
<input type=button id=p13UploadButton disabled="disabled" value="Upload" onclick="p13uploadFile()" onkeypress="return false" onkeydown="return false" />&nbsp;
<input type=button id=p13CutButton disabled="disabled" value="Cut" onclick="p13copyFile(1)" onkeypress="return false" onkeydown="return false" />&nbsp;
<input type=button id=p13CopyButton disabled="disabled" value="Copy" onclick="p13copyFile(0)" onkeypress="return false" onkeydown="return false" />&nbsp;
<input type=button id=p13PasteButton disabled="disabled" value="Paste" onclick="p13pasteFile()" onkeypress="return false" onkeydown="return false" />&nbsp;
<input type=button id=p13RefreshButton disabled="disabled" value="Refresh" onclick="p13folderup(9999)" onkeypress="return false" onkeydown="return false" />&nbsp;
</div>
</td>
</tr>
<tr>
<td style="background-color:#E4E9E7;height:28px">
<div style=float:right>
<select id=p13sortdropdown onchange=p13updateFiles()>
<option value=1 selected="selected">Sort by name</option>
<option value=2>Sort by size</option>
<option value=3>Sort by date</option>
<option value=4>Descend by name</option>
<option value=5>Descend by size</option>
<option value=6>Descend by date</option>
</select>
</div>
<div>&nbsp;&nbsp;<span id="p13currentpath"></span></div>
</td>
</tr>
</table>
<div id="p13filetable" style="width:100%;height:500px;overflow:auto;-webkit-user-select:none">
<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>
<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>
<span id="p13files"></span>
</div>
<table id="p13toolbarBottom" style=width:100% cellpadding=0 cellspacing=0>
<tr><td class=style6 style="text-align:left;padding:3px">&nbsp;<span id="p13bottomstatus"></span></td></tr>
</table>
</div>
<div id=p14 style=display:none>
<div id="p14title"><h1><span id=p14deviceName></span> - Intel&reg; AMT</h1></div>
<iframe id=p14iframe style="width:100%;height:650px;border:0;overflow:hidden" src="/commander.htm"></iframe>
</div>
<div id=p15 style=display:none>
<div id="p15title"><h1><span id=p15deviceName></span> - Console</h1></div>
<table cellpadding=0 cellspacing=0 style="width:100%;padding:0px;padding:0px;margin-top:0px">
<tr>
<td style=background:#C0C0C0>
<div style=float:right;padding-right:4px>
<div style=padding:4px;display:inline-block id=p15coreName title="Information about current core running on this agent"></div>
<input type=button id=p15uploadCore value="Agent Action" onclick=p15uploadCore(event) title="Change the agent Java Script code module" />
</div>
<div id="p15statetext" style=padding:4px></div>
</td>
</tr>
<tr>
<td>
<div style="background-color:gray"><div id="consoleprogressbar" style="height:2px;width:0%;background-color:red"></div></div>
</td>
</tr>
<tr>
<td style="background:black;text-align:center;height:500px;position:relative">
<div id=p15agentConsole style="background:black;margin:0;padding:0;color:lightgray;width:100%;max-width:930px;height:100%;text-align:left;overflow-y:scroll"><pre id=p15agentConsoleText></pre></div>
</td>
</tr>
<tr>
<td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
<table style="width:100%">
<tr>
<td style="width:99%">
<input id=p15consoleText style=width:100% onkeyup=p15consoleSend(event) onfocus=onConsoleFocus(1) onblur=onConsoleFocus(0) />
</td>
<td>&nbsp;</td>
<td style="width:1%"><input id="id_p15consoleClear" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Clear" onclick="p15consoleClear()"></td>
</tr>
</table>
</td>
</tr>
</table>
</div>
<div id=p16 style=display:none>
<div id="p16title"><h1><span id=p16deviceName></span> - Events</h1></div>
<div style=width:100%;height:24px;background-color:#d3d9d6;margin-bottom:4px>
<div class=style7 style=width:16px;height:100%;float:left>&nbsp;</div>
<div class=h1 style=height:100%;float:left>&nbsp;</div>
<!--<div class=style14 style=height:100%;float:left>&nbsp;&nbsp;<input id=p31deleteall type=button style=display:none value="Delete All..." />&nbsp;</div>-->
<div class=style14 style=height:100%;float:left>&nbsp;&nbsp;<input type=button value=Refresh onclick=refreshDeviceEvents() />&nbsp;</div>
<div class="auto-style1" style="height:100%;float:right">
Show
<select id=p16limitdropdown onchange=refreshDeviceEvents()>
<option value=60>Last 60</option>
<option value=120>Last 120</option>
<option value=250>Last 250</option>
<option value=500>Last 500</option>
<option value=1000>Last 1000</option>
</select>
<div style="height:100%;width:20px;float:right;background-color:#ffffff"></div>
<div class=h2 style=height:100%;float:right>&nbsp;</div>
</div>
</div>
<div id=p16events style="max-height:600px;overflow-y:scroll"></div>
</div>
<div id=p20 style=display:none>
<img id=MainMeshImage src="images/mesh-200.png" style=border-width:0px;height:200px;width:200px;float:right>
<h1><span id=p20meshName></span> - General</h1>
<p id=p20info></p>
</div>
<div id=p30 style=display:none>
<table style="width:100%" cellpadding="0" cellspacing="0">
<tr>
<td style=width:auto valign=top>
<div id="p30title">
<h1><span id=p30userName></span> - General</h1>
</div>
<div id=p30html></div>
</td>
<td style=width:20px></td>
<td style=width:200px>
<img id=MainUserImage src="images/user-200.png" style=border-width:0px;height:200px;width:200px>
<div style="width:100%;text-align:center"><strong><span id=MainUserState></span></strong></div>
</td>
</tr>
</table><br>
<div id=p30html2></div>
<div id=p30html3></div>
</div>
<div id=p31 style=display:none>
<h1><span id=p31userName></span> - Events</h1>
<div style=width:100%;height:24px;background-color:#d3d9d6;margin-bottom:4px>
<div class=style7 style=width:16px;height:100%;float:left>&nbsp;</div>
<div class=h1 style=height:100%;float:left>&nbsp;</div>
<!--<div class=style14 style=height:100%;float:left>&nbsp;&nbsp;<input id=p31deleteall type=button style=display:none value="Delete All..." />&nbsp;</div>-->
<div class=style14 style=height:100%;float:left>&nbsp;&nbsp;<input type=button value=Refresh onclick=refreshUsersEvents() />&nbsp;</div>
<div class="auto-style1" style="height:100%;float:right">
Show
<select id=p31limitdropdown onchange=refreshUsersEvents()>
<option value=60>Last 60</option>
<option value=120>Last 120</option>
<option value=250>Last 250</option>
<option value=500>Last 500</option>
<option value=1000>Last 1000</option>
</select>
<div style="height:100%;width:20px;float:right;background-color:#ffffff"></div>
<div class="h2" style="height:100%;float:right;">&nbsp;</div>
</div>
</div>
<div id=p31events style="max-height:600px;overflow-y:scroll"></div>
</div>
<br id="column_l_bottomgap" />
</div>
<div id=footer class=noselect>
<table cellpadding=0 cellspacing=10 style="width:100%">
<tr>
<td style="text-align:left;color:white">
{{{footer}}}
</td>
<td style="text-align:right">
<a id="verifyEmailId2" style="color:yellow;margin-left:3px;cursor:pointer;display:none" onclick="account_showVerifyEmail()">Verify Email</a>
<a style="margin-left:3px" href="terms">Terms &amp; Privacy</a>
</td>
</tr>
</table>
</div>
<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:160px;width:400px;display:none">
<div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
<div id=id_dialogclose style=float:right;padding:5px;cursor:pointer onclick=setDialogMode()><b>X</b></div>
<div id=id_dialogtitle style=padding:5px></div>
<div style=width:100%;margin:6px></div>
</div>
<div style="margin-right:16px;margin-left:8px">
<div id=dialog1 style="margin:auto;text-align:center;margin:3px">
<div id=id_dialogMessage style="padding:10px"></div>
</div>
<div id=dialog2 style="margin:auto;margin:3px">
<div id=id_dialogOptions></div>
</div>
<div id=dialog3 style="margin:auto;margin:3px">
<div style=height:26px>
<select id=d3uploadMode style=float:right;width:260px onchange=d3modechange()>
<option value=1>Local file upload</option>
<option value=2>Server file selection</option>
</select>
<div>File Selection</div>
</div>
<div id=d3localmode style=height:26px;display:none>
<form id=d3localmodeform method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame>
<input type=text id=d3attrib name=attrib style=display:none />
<input type=file id=d3localFile name=files style=float:right;width:260px onchange=d3setActions() />
<input type=submit id=d3submit style=display:none />
</form>
<div>Upload File</div>
</div>
<div id=d3servermode>
<div style="width:100%;background-color:#d3d9d6;text-align:left;padding:3px" valign=bottom>
<input type=button id=p3FolderUp disabled="disabled" onclick=d3folderup() value="Up" />&nbsp;
</div>
<div id=d3serverfiles style="width:100%;height:150px;background-color:white;padding:2px;border:1px solid gray;overflow-y:scroll"></div>
</div>
</div>
<div id=dialog7 style="margin:auto;margin:3px">
<div id="d7meshkvm">
<h4 style="width:100%;border-bottom:1px solid gray">Mesh Agent Remote Desktop</h4>
<div style="margin:3px 0 3px 0">
<select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl"></select>
<div style="height:20px">Quality</div>
</div>
<div style="margin:3px 0 3px 0">
<select id="d7bitmapscaling" style="float:right;width:200px;height:20px" dir="rtl">
<option selected=selected value=1024>100%</option>
<option value=896>87.5%</option>
<option value=768>75%</option>
<option value=640>62.5%</option>
<option value=512>50%</option>
<option value=384>37.5%</option>
<option value=256>25%</option>
<option value=128>12.5%</option>
</select>
<div style="height:20px">Scaling</div>
</div>
<div style="margin:3px 0 3px 0">
<select id="d7framelimiter" style="float:right;width:200px;height:20px" dir="rtl">
<option selected=selected value=50>Fast</option>
<option value=100>Medium</option>
<option value=400>Slow</option>
<option value=1000>Very slow</option>
</select>
<div style="height:20px">Frame rate</div>
</div>
</div>
<div id="d7amtkvm">
<h4 style="width:100%;border-bottom:1px solid gray">Intel&reg; AMT Hardware KVM</h4>
<div style='height:26px'>
<select id="d7desktopmode" style="float:right;width:200px">
<option value="1">RLE8, Fastest</option>
<option value="2">RLE16, Recommended</option>
<option value="3">RAW8, Slow</option>
<option value="4">RAW16, Very Slow</option>
</select>
<div>Image Encoding</div>
</div>
<div style="height:60px">
<div style="float:right;border:1px solid #666;width:200px;height:60px;overflow-y:scroll;background-color:white">
<input type="checkbox" id='d7showfocus'>Show Focus Tool<br>
<input type="checkbox" id='d7showcursor'>Show Local Mouse Cursor<br>
</div>
<div>Other Settings</div>
</div>
</div>
</div>
</div>
<div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:4px">
<input id="idx_dlgCancelButton" type="button" value="Cancel" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">
<input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)">
<div style="height:25px"><input id=idx_dlgDeleteButton type=button value=Delete style="width:80px;display:none" onclick="dialogclose(2)"></div>
</div>
</div>
<iframe name="fileUploadFrame" style=display:none></iframe>
<form style=display:none method=post action=uploadfile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p5fileDragName name="name"><input id=p5fileDragSize name="size"><input id=p5fileDragType name="type"><input id=p5fileDragData name="data"><input id=p5fileDragLink name="link"><input type=submit id=p5loginSubmit2 style=display:none /></form>
<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>
<audio id="chimes"><source src="sounds/chimes.mp3" type="audio/mp3"></audio>
</div>
</div>
<script type="text/javascript">
var args;
var powerStatetable = ['', 'Powered', 'Sleep', 'Sleep', 'Sleep', 'Hibernating', 'Power off', 'Present'];
var StatusStrs = ['Disconnected', 'Connecting...', 'Setup...', 'Connected', 'Intel&reg; AMT Connected'];
var sort = 0;
var searchFocus = 0;
var mapSearchFocus = 0;
var consoleFocus = 0;
var showHostnames = false;
var meshserver = null;
var meshes = {};
var meshcount = 0;
var nodes = [];
var filetree = {};
var userinfo = null;
var serverinfo = null;
var events = [];
var users = null;
var wssessions = null;
var nodeShortIdent = 0;
var desktop;
var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 50 };
var multidesktopsettings = { quality: 20, scaling: 128, framerate: 1000 };
var terminal;
var files;
var debugLevel = {{{debuglevel}}};
var features = {{{features}}};
var multiDesktop = {};
var multiDesktopFilter = null;
var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}";
var amtScanResults = null;
var debugmode = false;
var clickOnce = (((features & 256) != 0) && detectClickOnce());
var attemptWebRTC = ((features & 128) != 0);
var webPageFullScreen = getstore('webPageFullScreen', false);;
if (webPageFullScreen == 'false') { webPageFullScreen = false; }
function startup() {
if ((features & 32) == 0) {
// Guard against other site's top frames (web bugs).
var loc = null;
try { loc = top.location.toString().toLowerCase(); } catch (e) { }
if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
}
toggleFullScreen();
// Check if we are in debug mode
args = parseUriArgs();
debugmode = (args.debug == 1);
if (args.webrtc != null) { attemptWebRTC = (args.webrtc == 1); }
QV('p13AutoConnect', debugmode); // Files
QV('autoconnectbutton2', debugmode); // Terminal
QV('autoconnectbutton1', debugmode); // Desktop
// Setup page visuals
if (args.hide) {
var hide = parseInt(args.hide);
QV('masthead', !(hide & 1));
QV('topbarmaster', !(hide & 2));
QV('footer', !(hide & 4));
QV('p10title', !(hide & 8));
QV('p11title', !(hide & 8));
QV('p12title', !(hide & 8));
QV('p13title', !(hide & 8));
QV('p14title', !(hide & 8));
QV('p15title', !(hide & 8));
QV('p16title', !(hide & 8));
}
p1updateInfo();
// Setup the context menu
document.onclick = function (e) { hideContextMenu(); }
document.onkeypress = ondockeypress;
document.onkeydown = ondockeydown;
document.onkeyup = ondockeyup;
window.onresize = center;
center();
// Connect to the mesh server
meshserver = MeshServerCreateControl("{{{domainurl}}}");
meshserver.onStateChanged = onStateChanged;
meshserver.onMessage = onMessage;
meshserver.Start();
// Setup page controls
Q('sortselect').selectedIndex = sort = getstore("sort", 0);
Q('sizeselect').selectedIndex = getstore("viewsize", 1);
Q('SearchInput').value = getstore("search", "");
showHostnames = (getstore("showHostnames", 0) == 1);
Q('HostnameCheckBox').checked = showHostnames;
Q('viewselect').value = getstore("deviceView", 1);
Q('DeskControl').checked = (getstore('DeskControl', 1) == 1);
// Display the page devices
onSortSelectChange();
onSearchInputChanged();
updateDevices();
// Setup upload drag & drop
Q('p5filetable').addEventListener("drop", p5fileDragDrop, false);
Q('p5filetable').addEventListener("dragover", p5fileDragOver, false);
Q('p5filetable').addEventListener("dragleave", p5fileDragLeave, false);
//Q('p5fileCatchAllInput').addEventListener("drop", p5fileDragDrop, false);
//Q('p5fileCatchAllInput').addEventListener("dragover", p5fileDragOver, false);
//Q('p5fileCatchAllInput').addEventListener("dragleave", p5fileDragLeave, false);
// Setup upload drag & drop
Q('p13filetable').addEventListener("drop", p13fileDragDrop, false);
Q('p13filetable').addEventListener("dragover", p13fileDragOver, false);
Q('p13filetable').addEventListener("dragleave", p13fileDragLeave, false);
// Timeline update interval
setInterval(updateDeviceTimeline, 120000); // Check every 2 minutes
// Load desktop settings
var t = localStorage.getItem('desktopsettings');
if (t != null) { desktopsettings = JSON.parse(t); }
t = localStorage.getItem('multidesktopsettings');
if (t != null) { multidesktopsettings = JSON.parse(t); }
applyDesktopSettings();
// Terminal special keys
var x = '';
for (var c = 1; c < 27; c++) x += "<option value='" + c + "'>Ctrl-" + String.fromCharCode(64 + c) + " (" + c + ")</option>";
QH('specialkeylist', x);
}
// Toggle the web page to full screen
function toggleFullScreen(toggle) {
if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
if (webPageFullScreen == false) {
QS('container').width = '960px';
QS('container')['border-right'] = '1px solid #b7b7b7';
QS('container')['border-left'] = '1px solid #b7b7b7';
QS('container')['min-width'] = '960px';
//QS('column_l').padding = '0 15px';
QS('column_l').width = '930px';
} else {
QS('container').width = '100%';
QS('container')['border-right'] = '0';
QS('container')['border-left'] = '0';
QS('container')['min-width'] = '700px';
//QS('column_l').padding = '0';
QS('column_l').width = 'calc(100% - 30px)';
}
}
function getNodeFromId(id) {
for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; }
return null;
}
function reload() { window.location.href = window.location.href; }
function onStateChanged(server, state) {
if (state == 0) {
// Control web socket disconnected
setDialogMode(0); // Close any dialog boxes if present
go(0); // Go to disconnection panel
// Clean up
powerTimeline = null;
powerTimelineReq = null;
powerTimelineNode = null;
powerTimelineUpdate = null;
deleteAllNotifications(); // Close and clear notifications if present
hideContextMenu(); // Hide the context menu if present
QV('verifyEmailId2', false);
QV('logoutControl', false);
setTimeout(serverPoll, 5000);
} else if (state == 2) {
// Fetch list of meshes, nodes, files
meshserver.send({ action: 'meshes' });
meshserver.send({ action: 'nodes' });
meshserver.send({ action: 'files' });
}
}
// Poll the server, if it responds, refresh the page.
function serverPoll() {
xdr = null;
try { xdr = new XDomainRequest(); } catch (e) { }
if (!xdr) xdr = new XMLHttpRequest();
xdr.open("HEAD", window.location.href);
xdr.timeout = 15000;
xdr.onload = function () { reload(); };
xdr.onerror = xdr.ontimeout = function () { setTimeout(serverPoll, 10000); };
xdr.send();
}
// Return true if this browser supports clickonce
function detectClickOnce() {
for (var i in window.navigator.mimeTypes) { if (window.navigator.mimeTypes[i].type == "application/x-ms-application") { return true; } }
var userAgent = window.navigator.userAgent.toUpperCase();
return (userAgent.indexOf('.NET CLR 3.5') >= 0) || (userAgent.indexOf('(WINDOWS NT ') >= 0);
}
function updateSiteAdmin() {
var noServerBackup = {{{noServerBackup}}};
var siteRights = userinfo.siteadmin;
if (noServerBackup == 1) { siteRights &= 0xFFFFFFFA; } // If not server backups allowed, remove server backup and restore permissions
// Update account actions
QV('p2AccountActions', (features & 4) == 0); // Hide Account Actions if in single user mode
QV('p2ServerActions', siteRights & 5);
QV('p2ServerActionsBackup', siteRights & 1);
QV('p2ServerActionsRestore', siteRights & 4);
QV('p2ServerActionsVersion', siteRights & 16);
QV('MainMenuMyFiles', siteRights & 8);
if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { setDialogMode(0); go(1); }
if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
// Update user management state
if ((userinfo.siteadmin & 2) != 0)
{
// We are user administrator
if (users == null) { meshserver.send({ action: 'users' }); }
if (wssessions == null) { meshserver.send({ action: 'wssessioncount' }); }
} else {
// We are not user administrator
users = null;
wssessions = null;
updateUsers();
if (xxcurrentView == 4 || ((xxcurrentView >= 30) && (xxcurrentView < 40))) { setDialogMode(0); go(1); currentUser = null; }
}
meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
QV('p2deleteall', userinfo.siteadmin == 0xFFFFFFFF);
}
function onMessage(server, message) {
switch (message.action) {
case 'serverinfo': {
serverinfo = message.serverinfo;
break;
}
case 'userinfo': {
userinfo = message.userinfo;
updateSiteAdmin();
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
break;
}
case 'users': {
users = {};
for (var m in message.users) { users[message.users[m]._id] = message.users[m]; }
updateUsers();
break;
}
case 'wssessioncount': {
wssessions = message.wssessions;
updateUsers();
break;
}
case 'meshes': {
meshes = {};
for (var m in message.meshes) { meshes[message.meshes[m]._id] = message.meshes[m]; }
updateMeshes();
updateDevices();
break;
}
case 'files': {
filetree = setupBackPointers(message.filetree);
updateFiles();
d3updatefiles();
break;
}
case 'nodes': {
nodes = [];
for (var m in message.nodes) {
for (var n in message.nodes[m]) {
if (!meshes[m]) { console.log('Invalid mesh (1): ' + m); continue; }
message.nodes[m][n].namel = message.nodes[m][n].name.toLowerCase();
if (message.nodes[m][n].host) { message.nodes[m][n].hostl = message.nodes[m][n].host.toLowerCase(); } else { message.nodes[m][n].hostl = message.nodes[m][n].namel; }
message.nodes[m][n].meshnamel = meshes[m].name.toLowerCase();
message.nodes[m][n].meshid = m;
message.nodes[m][n].state = (message.nodes[m][n].state)?(message.nodes[m][n].state):0;
message.nodes[m][n].desc = message.nodes[m][n].desc;
if (!message.nodes[m][n].icon) message.nodes[m][n].icon = 1;
message.nodes[m][n].ident = ++nodeShortIdent;
nodes.push(message.nodes[m][n]);
}
}
onSortSelectChange();
onSearchInputChanged();
updateDevices();
refreshMap(false, true);
if (xxcurrentView == 0) { if ('{{viewmode}}' != '') { go({{viewmode}}); } else { setDialogMode(0); go(1); } }
if ('{{currentNode}}' != '') { gotoDevice('{{currentNode}}',{{viewmode}});}
break;
}
case 'powertimeline': {
if (message.nodeid != powerTimelineReq) break;
powerTimelineNode = message.nodeid;
powerTimeline = message.timeline;
powerTimelineUpdate = Date.now() + 300000; // Update every 5 minutes
if (currentNode._id == message.nodeid) { drawDeviceTimeline(); }
break;
}
case 'msg': {
// Check if this is a message from a node
if (message.nodeid != null) {
var index = -1;
for (var i in nodes) { if (nodes[i]._id == message.nodeid) { index = i; break; } }
if (index != -1) {
// Node was found, dispatch the message
if (message.type == 'console') { p15consoleReceive(nodes[index], message.value); } // This is a console message.
else if (message.type == 'notify') { // This is a notification message.
var n = { text:message.value };
if (message.nodeid != null) { n.nodeid = message.nodeid; }
if (message.tag != null) { n.tag = message.tag; }
addNotification(n);
} else if (message.type == 'ps') {
showDeskToolsProcesses(message);
}
}
} else {
if (message.type == 'notify') { // This is a notification message.
var n = { text:message.value };
if (message.tag != null) { n.tag = message.tag; }
addNotification(n);
}
}
break;
}
case 'getnetworkinfo': {
if ((currentNode._id == message.nodeid) && (xxdialogMode == 2) && (xxdialogTag == 'if' + message.nodeid)) {
if (message.netif == null) {
QH('d2netinfo', 'No network interface information available for this device.');
} else {
var x = '<div style=width:100%;max-height:260px;overflow-x:hidden;overflow-y:auto;line-height:160%>';
x += addHtmlValue2('Last Updated', new Date(message.updateTime).toLocaleString());
if (currentNode.publicip) { x += addHtmlValue2('Public IP address', currentNode.publicip); }
for (var i in message.netif) {
var net = message.netif[i];
x += '<hr />'
if (net.name) { x += addHtmlValue2('Name', '<b>' + EscapeHtml(net.name) + '</b>'); }
if (net.desc) { x += addHtmlValue2('Description', EscapeHtml(net.desc).replace('(R)', '&reg;').replace('(r)', '&reg;')); }
if (net.dnssuffix) { x += addHtmlValue2('DNS suffix', EscapeHtml(net.dnssuffix)); }
if (net.mac) { x += addHtmlValue2('MAC address', EscapeHtml(net.mac.toUpperCase())); }
if (net.v4addr) { x += addHtmlValue2('IPv4 address', EscapeHtml(net.v4addr)); }
if (net.v4mask) { x += addHtmlValue2('IPv4 mask', EscapeHtml(net.v4mask)); }
if (net.v4gateway) { x += addHtmlValue2('IPv4 gateway', EscapeHtml(net.v4gateway)); }
if (net.gatewaymac) { x += addHtmlValue2('Gateway MAC', EscapeHtml(net.gatewaymac)); }
}
x += '</div>';
QH('d2netinfo', x);
}
}
break;
}
case 'serverversion': {
if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerUpdate')) {
var x = '<div style=width:100%;max-height:260px;overflow-x:hidden;overflow-y:auto;line-height:160%>';
if (!message.current) { message.current = 'Unknown'; }
if (!message.latest) { message.latest = 'Unknown'; }
x += addHtmlValue2('Current Version', '<b>' + EscapeHtml(message.current) + '</b>');
x += addHtmlValue2('Latest Version', '<b>' + EscapeHtml(message.latest) + '</b>');
x += '</div>';
if (message.current == message.latest) {
setDialogMode(2, "MeshCentral Version", 1, null, x);
} else {
setDialogMode(2, "MeshCentral Version", 3, server_showVersionDlgEx, x + '<br /><input id=d2updateCheck type=checkbox onclick=server_showVersionDlgUpdate() /> Check and click OK to start server self-update.');
server_showVersionDlgUpdate();
}
}
break;
}
case 'events': {
if ((message.nodeid != null) && (message.nodeid == currentNode._id)) {
currentDeviceEvents = message.events;
devevents_update();
} else if ((message.user != null) && (message.user == currentUser.name)) {
currentUserEvents = message.events;
userEvents_update();
} else {
events = message.events;
events_update();
}
break;
}
case 'getcookie': {
if (message.tag == 'clickonce') {
var basicPort = "{{{serverRedirPort}}}"==""?"{{{serverPublicPort}}}":"{{{serverRedirPort}}}";
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 + "&HOL=1";
window.open(rdpurl, '_blank');
}
break;
}
case 'getNotes':{
var n = Q('d2devNotes');
if (n && (message.id == decodeURIComponent(n.attributes['noteid'].value))) {
if (message.notes) { QH('d2devNotes', decodeURIComponent(message.notes)); } else { QH('d2devNotes', ''); }
var ro = n.attributes['ro'].value == 'true';
if (ro == false) { // If we have permissions, set read/write on this note.
n.removeAttribute('readonly');
QE('idx_dlgOkButton', true);
QV('idx_dlgOkButton', true);
focusTextBox('d2devNotes');
}
}
break;
}
case 'event': {
if (!message.event.nolog) {
events.unshift(message.event);
var eventLimit = parseInt(p3limitdropdown.value);
while (events.length > eventLimit) { events.pop(); } // Remove element(s) at the end
events_update();
}
switch (message.event.action) {
case 'accountcreate':
case 'accountchange': {
// An account was created or changed
if (userinfo.name == message.event.account.name) {
var newsiteadmin = message.event.account.siteadmin?message.event.account.siteadmin:0;
var oldsiteadmin = userinfo.siteadmin?userinfo.siteadmin:0;
if ((message.event.account.quota != userinfo.quota) || (((userinfo.siteadmin & 8) == 0) && ((message.event.account.siteadmin & 8) != 0))) { meshserver.send({ action: 'files' }); }
userinfo = message.event.account;
if (oldsiteadmin != newsiteadmin) updateSiteAdmin();
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
}
if (users == null) break;
users[message.event.account._id] = message.event.account;
updateUsers();
break;
}
case 'accountremove': {
// An account was removed
if (users == null) break;
delete users['user/{{{domain}}}/' + message.event.username.toLowerCase()];
updateUsers();
break;
}
case 'createmesh': {
// A new mesh was created
if (message.event.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()] != 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.
meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
updateMeshes();
updateDevices();
meshserver.send({ action: 'files' });
}
break;
}
case 'meshchange': {
// Update mesh information
if (meshes[message.event.meshid] == null) {
// This is a new mesh for us
meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
meshserver.send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh).
} else {
// This is an existing mesh
meshes[message.event.meshid].name = message.event.name;
meshes[message.event.meshid].desc = message.event.desc;
meshes[message.event.meshid].links = message.event.links;
// Check if we lost rights to this mesh in this change.
if (meshes[message.event.meshid].links['user/{{{domain}}}/' + userinfo.name.toLowerCase()] == null) {
if ((xxcurrentView == 20) && (currentMesh == meshes[message.event.meshid])) go(2);
delete meshes[message.event.meshid];
// Delete all nodes in that mesh
var newnodes = [];
for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } }
nodes = newnodes;
// If we are looking at a node in the deleted mesh, move back to "My Devices"
if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); }
}
}
updateMeshes();
updateDevices();
meshserver.send({ action: 'files' });
// If we are looking at a mesh that is now deleted, move back to "My Account"
if (xxcurrentView == 20 && currentMesh._id == message.event.meshid) { p20updateMesh(); }
break;
}
case 'deletemesh': {
// Delete the mesh
if (meshes[message.event.meshid]) {
delete meshes[message.event.meshid];
updateMeshes();
meshserver.send({ action: 'files' });
}
// Delete all nodes in that mesh
var newnodes = [];
for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } }
nodes = newnodes;
updateDevices();
// If we are looking at a mesh that is now deleted, move back to "My Account"
if (xxcurrentView >= 20 && xxcurrentView < 30 && currentMesh._id == message.event.meshid) { setDialogMode(0); go(2); }
// If we are looking at a node in the deleted mesh, move back to "My Devices"
if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && currentNode.meshid == message.event.meshid) { setDialogMode(0); go(1); }
break;
}
case 'addnode': {
var node = message.event.node;
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.
node.namel = node.name.toLowerCase();
if (node.host) { node.hostl = node.host.toLowerCase(); } else { node.hostl = node.namel; }
node.meshnamel = meshes[node.meshid].name.toLowerCase();
node.state = 0;
if (!node.icon) node.icon = 1;
node.ident = ++nodeShortIdent;
nodes.push(node);
onSortSelectChange();
onSearchInputChanged();
updateDevices();
updateMapMarkers();
break;
}
case 'removenode': {
var index = -1;
for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
if (index != -1) {
var node = nodes[index];
if (currentNode == node) {
if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); }
delete currentNode; // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
}
nodes.splice(index, 1);
updateDevices();
updateMapMarkers();
}
break;
}
case 'changenode': {
var index = -1;
for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
if (index != -1) {
var node = nodes[index];
// Change the node
node.name = message.event.node.name;
node.host = message.event.node.host;
node.desc = message.event.node.desc;
node.publicip = message.event.node.publicip;
node.iploc = message.event.node.iploc;
node.wifiloc = message.event.node.wifiloc;
node.gpsloc = message.event.node.gpsloc;
node.tags = message.event.node.tags;
node.userloc = message.event.node.userloc;
if (message.event.node.agent != null) {
if (node.agent == null) node.agent = {};
if (message.event.node.agent.ver != null) { node.agent.ver = message.event.node.agent.ver; }
if (message.event.node.agent.id != null) { node.agent.id = message.event.node.agent.id; }
if (message.event.node.agent.caps != null) { node.agent.caps = message.event.node.agent.caps; }
if (message.event.node.agent.core != null) { node.agent.core = message.event.node.agent.core; } else { if (node.agent.core) { delete node.agent.core; } }
node.agent.tag = message.event.node.agent.tag;
}
if (message.event.node.intelamt != null) {
if (node.intelamt == null) node.intelamt = {};
if (message.event.node.intelamt.host != null) { node.intelamt.user = message.event.node.intelamt.host; }
if (message.event.node.intelamt.user != null) { node.intelamt.user = message.event.node.intelamt.user; }
if (message.event.node.intelamt.tls != null) { node.intelamt.tls = message.event.node.intelamt.tls; }
if (message.event.node.intelamt.ver != null) { node.intelamt.ver = message.event.node.intelamt.ver; }
if (message.event.node.intelamt.state != null) { node.intelamt.state = message.event.node.intelamt.state; }
}
node.namel = node.name.toLowerCase();
if (node.host) { node.hostl = node.host.toLowerCase(); } else { node.hostl = node.namel; }
if (message.event.node.icon) { node.icon = message.event.node.icon; }
onSortSelectChange(true);
drawNotifications();
refreshDevice(node._id);
updateMapMarkers();
if ((currentNode == node) && (xxdialogMode != null) && (xxdialogTag == '@xxmap')) { p10showNodeLocationDialog(); }
}
break;
}
case 'nodeconnect': {
// Indicated a node has changed connectivity state
var index = -1;
for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
if (index != -1) {
var node = nodes[index];
// Change the node connection state
node.conn = message.event.conn;
node.pwr = message.event.pwr;
updateDevices();
updateMapMarkers();
refreshDevice(node._id);
}
break;
}
case 'wssessioncount': {
// Update the active web socket session count for a user
if (wssessions != null) {
if (message.event.count == 0 && wssessions['user/{{{domain}}}/' + message.event.username.toLowerCase()]) {
delete wssessions['user/{{{domain}}}/' + message.event.username.toLowerCase()];
} else {
wssessions['user/{{{domain}}}/' + message.event.username.toLowerCase()] = message.event.count;
}
updateUsers();
}
break;
}
case 'clearevents': {
events = [];
events_update();
break;
}
case 'login': {
// Update the last login time
if (users != null && users['user/{{{domain}}}/' + message.event.username.toLowerCase()]) { users['user/{{{domain}}}/' + message.event.username.toLowerCase()].login = message.event.time; }
break;
}
case 'scanamtdevice': {
// Populate the Intel AMT scan dialog box with the result of the RMCP scan
if ((xxdialogMode == null) || (!Q('dp1range')) || (Q('dp1range').value != message.event.range)) return;
var x = '';
if (message.event.results == null) {
// The scan could not occur because of an error. Likely the user range was invalid.
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>';
} else {
// Go thru all the results and populate the dialog box
amtScanResults = message.event.results;
for (var i in message.event.results) {
var r = message.event.results[i], shortname = r.hostname;
if (shortname.length > 20) { shortname = shortname.substring(0, 20) + '...'; }
var str = '<b title="' + EscapeHtml(r.hostname) + '">' + EscapeHtml(shortname) + '</b> - v' + r.ver;
if (r.state == 2) { if (r.tls == 1) { str += ' with TLS.'; } else { str += ' without TLS.'; } } else { str += ' not activated.'; }
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>';
}
// If no results where found, display a nice message
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>'; }
}
// Set the html in the dialog box and re-enable the scan button
QH('dp1results', x);
QE('dp1range', true);
QE('dp1rangebutton', true);
break;
}
case 'notify': {
var n = { text: message.event.value };
if (message.event.tag != null) { n.tag = message.event.tag; }
addNotification(n);
break;
}
}
break;
}
}
}
//
// MY DEVICES
//
function onHostnameCheckBox() {
showHostnames = Q('HostnameCheckBox').checked;
putstore("showHostnames", showHostnames ? 1 : 0);
onSortSelectChange();
return;
}
function onDeviceViewChange() {
putstore("deviceView", Q('viewselect').value);
putstore("viewsize", Q('sizeselect').value);
updateDevices();
}
function ondockeypress(e) {
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) return desktop.m.handleKeys(e);
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeys(e);
if (!xxdialogMode && xxcurrentView == 15) return agentConsoleHandleKeys(e);
if (xxdialogMode || xxcurrentView != 1) return;
if (e.ctrlKey == true && e.charCode == 96) {
showHostnames = !showHostnames;
Q('HostnameCheckBox').value = showHostnames;
putstore("showHostnames", showHostnames ? 1 : 0);
onSortSelectChange();
return;
}
if (e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
if (Q('viewselect').value < 3) {
var processed = 0;
if (e.key) {
if (e.key.length === 1 && searchFocus == 0) { Q('SearchInput').value = ((Q('SearchInput').value + e.key)); processed = 1; }
if (e.keyCode == 8 && searchFocus == 0) { var x = Q('SearchInput').value; Q('SearchInput').value = x.substring(0, x.length - 1); processed = 1; }
if (e.keyCode == 27) { Q('SearchInput').value = ''; processed = 1; }
} else {
if (e.charCode != 0 && searchFocus == 0) { Q('SearchInput').value = ((Q('SearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
}
if (processed > 0) { if (processed == 1) { onSearchInputChanged(); } return haltEvent(e); }
}
if (Q('viewselect').value == 3) {
if (e.key) {
if (e.key.length === 1 && mapSearchFocus == 0) { Q('mapSearchLocation').value = ((Q('mapSearchLocation').value + e.key)); processed = 1; }
//if (e.keyCode == 8 && mapSearchFocus == 0) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = x.substring(0, x.length - 1); processed = 1; }
if (e.keyCode == 27) { Q('mapSearchLocation').value = ''; mapCloseSearchWindow(); processed = 1; }
if (e.keyCode == 13) { getSearchLocation(); }
} else {
if (e.charCode != 0 && mapSearchFocus == 0) { Q('mapSearchLocation').value = ((Q('mapSearchLocation').value + String.fromCharCode(e.charCode))); processed = 1; }
}
}
}
function ondockeydown(e) {
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) { return desktop.m.handleKeyDown(e); }
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { return terminal.m.TermHandleKeyDown(e); }
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { haltEvent(e); return false; } // F5 Refresh on files
if (!xxdialogMode && xxcurrentView == 15) { return agentConsoleHandleKeys(e); }
if (xxdialogMode || xxcurrentView != 1 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
var processed = 0;
if (Q('viewselect').value < 3) {
if (e.keyCode === 8 && searchFocus == 0) { var x = Q('SearchInput').value; Q('SearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
if (e.keyCode === 27) { Q('SearchInput').value = ''; processed = 1; }
if (processed > 0) { if (processed == 1) { onSearchInputChanged(); } return haltEvent(e); }
}
if (Q('viewselect').value == 3) {
if (e.keyCode === 8 && mapSearchFocus == 0) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = (x.substring(0, x.length - 1)); processed = 1; }
if (e.keyCode === 27) { Q('mapSearchLocation').value = ''; mapCloseSearchWindow(); processed = 1; }
}
}
function ondockeyup(e) {
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) return desktop.m.handleKeyUp(e);
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeyUp(e);
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { p13folderup(9999); haltEvent(e); return false; } // F5 Refresh on files
if (xxdialogMode && e.keyCode == 27) { dialogclose(0); }
if (xxdialogMode || xxcurrentView != 0 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
if (Q('viewselect').value < 3) { if ((e.keyCode === 8 && searchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
if (Q('viewselect').value == 3) { if ((e.keyCode === 8 && mapSearchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
}
var deviceHeaderId = 0;
var deviceHeaderCount;
var deviceHeaders = {};
var oldviewmode = 0;
function updateDevices() {
var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, view = Q('viewselect').value, groups = {}, groupCount = {};
QV('xdevices', view < 4);
QV('xdevicesmap', view == 4);
QV('devListToolbar', view < 3);
QV('kvmListToolbar', view == 3);
QV('devMapToolbar', view == 4);
QV('devListToolbarSize', view == 3);
QV('NoMeshesPanel', meshcount == 0);
QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0));
QV('devListToolbarSort', (meshcount != 0) && (nodes.length > 0) && (view < 4));
if ((meshcount == 0) || (nodes.length == 0)) { view = 1; }
if (view == 4) {
setTimeout( function() { if (xxmap.map != null) { xxmap.map.updateSize(); } }, 200);
// TODO
} else {
// 3 wide, list view or desktop view
deviceHeaderId = 0;
deviceHeaderCount = {};
deviceHeaderTotal = 0;
deviceHeaders = {};
deviceHeadersTitles = {};
var kvmDivs = [];
// Save the list of currently checked nodeid's
var checkedNodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
for (var i in elements) { if (elements[i].checked) { checkedNodeids.push(elements[i].value); } }
if ((oldviewmode < 3) && (view == 3)) { multiDesktopFilter = checkedNodeids; }
else if ((oldviewmode == 3) && (view < 3)) { checkedNodeids = multiDesktopFilter; }
// Go thru the list of nodes and display them
for (var i in nodes) {
if (nodes[i].v == false) continue;
var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
if (meshlinks == null) continue;
var meshrights = meshlinks.rights;
if ((view == 3) && (mesh2.mtype == 1)) continue;
if (sort == 0) {
// Mesh header
if (nodes[i].meshid != current) {
deviceHeaderSet();
var extra = '';
if (meshes[nodes[i].meshid].mtype == 1) { extra = '<span class=devHeaderx>, Intel&reg; AMT only</span>'; }
if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
r += '<div class=DevSt style=width:100%;padding-top:4px><span style=float:right>';
r += getMeshActions(mesh2, meshrights);
r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + nodes[i].meshid + '")>' + EscapeHtml(meshes[nodes[i].meshid].name) + '</span>' + extra + '<span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx></span></div>';
current = nodes[i].meshid;
displayedMeshes[current] = 1;
c = 0;
}
} else if (sort == 1) {
// Power header
if (nodes[i].pwr !== current) {
deviceHeaderSet();
if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
r += '<div class=DevSt style=width:100%;padding-top:4px><span>' + PowerStateStr2(nodes[i].pwr) + '</span><span id=DevxHeader' + deviceHeaderId + ' class="devHeaderx"></span></div>';
current = nodes[i].pwr;
c = 0;
}
} else if (sort == 2) {
// Device header
if (current == null) { current = '1'; }
}
count++;
var title = EscapeHtml(nodes[i].name);
if (title.length == 0) { title = '<i>None</i>'; }
if ((nodes[i].host != null) && (nodes[i].host.length > 0)) { title += " / " + EscapeHtml(nodes[i].host); }
var name = EscapeHtml(nodes[i].name);
if (showHostnames == true && nodes[i].host != null) name = EscapeHtml(nodes[i].host);
if (name.length == 0) { name = '<i>None</i>'; }
// Node
var icon = nodes[i].icon;
var nodestate = NodeStateStr(nodes[i]);
if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; }
if (view == 1) {
r += '<div id=devs style=display:inline-block;width:301px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div><div style=height:100%;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class="i' + icon + '" style=width:50px;float:left></div><div style=height:100%><div class=g1></div><div class=e2><div class=e1 title="' + title + '">' + name + '</div><div>' + nodestate + '</div></div><div class=g2></div></div></div></div>';
} else if (view == 2) {
r += '<tr><td><div id=devs class=bar18 style=height:18px;width:100%;font-size:medium>';
r += '<div style=width:22px;float:left;background-color:white><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div>';
r += '<div style=float:left;height:18px;width:18px;background-color:white onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class=j' + icon + ' style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
r += '<div style=cursor:pointer;font-size:14px title="' + title + '" onclick=gotoDevice(\'' + nodes[i]._id + '\')><span style=float:right>' + nodestate + '</span><span style=width:300px>' + name + '</span></div></div></td></tr>';
} else if ((view == 3) && (nodes[i].conn & 1) && ((meshrights & 8) != 0)) {
if ((multiDesktopFilter.length == 0) || (multiDesktopFilter.indexOf('devid_' + nodes[i]._id) >= 0)) {
r += '<div id=devs style=display:inline-block;margin:1px;background-color:lightgray;border-radius:5px;position:relative><div style=padding:3px;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\',11)>';
//r += '<input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox style=float:left>';
r += '<div class="j' + icon + '" style=width:16px;float:left></div>&nbsp;' + name + '</div>';
r += '<span onclick=gotoDevice(\'' + nodes[i]._id + '\')></span><div id=xkvmid_' + nodes[i]._id.split('/')[2] + '><div id=skvmid_' + nodes[i]._id.split('/')[2] + ' style="position:absolute;color:white;left:5px;top:27px;text-shadow:0px 0px 5px #000;z-index:1000;cursor:default" onclick=toggleKvmDevice(\'' + nodes[i]._id + '\')>Disconnected</div></div>';
r += '</div>';
kvmDivs.push(nodes[i]._id);
}
}
// If we are displaying devices by group, put the device in the right group.
if ((sort == 3) && (r != '')) {
if (nodes[i].tags) {
for (var j in nodes[i].tags) {
var tag = nodes[i].tags[j];
if (groups[tag] == null) { groups[tag] = r; groupCount[tag] = 1; } else { groups[tag] += r; groupCount[tag] += 1; }
if (view == 3) break;
}
}
r = '';
}
deviceHeaderTotal++;
if (typeof deviceHeaderCount[nodes[i].state] == 'undefined') { deviceHeaderCount[nodes[i].state] = 1; } else { deviceHeaderCount[nodes[i].state]++; }
}
// If displaying devices by groups, sort the group names and display the devices.
if (sort == 3) {
var groupNames = [];
for (var i in groups) { groupNames.push(i); }
groupNames.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); });
for (var j in groupNames) {
var i = groupNames[j]; r += '<div class=DevSt style=width:100%;padding-top:4px><span>' + i + '</span><span class="devHeaderx">, ' + groupCount[i] + ' device' + ((groupCount[i] > 1)?'s':'') + '</span></div>' + groups[i];
}
}
// If there is nothing to display, explain the problem
if (r == '') {
if ((Q('SearchInput').value == '') && (sort == 3)) {
r = '<div style="margin:30px">No devices are included in any groups, click on a device\'s \"Groups\" to add to a group.</div>';
} else {
r = '<div style="margin:30px">No devices matching this search.</div>';
}
}
if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding
// Display all empty meshes, we need to do this because users can add devices to these at any time.
if ((sort == 0) && (Q('SearchInput').value == '') && (view < 3)) {
for (var i in meshes) {
var mesh = meshes[i], meshlink = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
if (meshlink != null) {
var meshrights = meshlink.rights;
if (displayedMeshes[mesh._id] == null) {
if ((current != '') && (r != '')) { r += '</tr></table>'; }
r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span style=float:right>';
r += getMeshActions(mesh, meshrights);
r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></td></tr><tr>';
if (mesh.mtype == 1) {
r += '<td><div style=padding:10px><i>No Intel&reg; AMT devices in this mesh';
if ((meshrights & 4) != 0) { r += ', <a style=cursor:pointer onclick=addDeviceToMesh(\"' + mesh._id + '\")>add one</a>'; }
}
if (mesh.mtype == 2) {
r += '<td><div style=padding:10px><i>No devices in this mesh';
if ((meshrights & 4) != 0) { r += ', <a style=cursor:pointer onclick=addAgentToMesh(\"' + mesh._id + '\")>add one</a>'; }
}
r += '.</i></div></td>';
current = mesh._id;
count++;
}
}
}
}
r += '</tr></table><div style=height:1px></div>'; // This height of 1 div fixes a problem in Linux firefox browsers
// Add a "Add Mesh" option
r += '<div style=border-top-style:solid;border-top-width:1px;border-top-color:#DDDDDD;cursor:pointer;font-size:10px>';
if ((view < 3) && (sort == 0) && (meshcount > 0)) { r += '<a onclick=account_createMesh() title="Create a new group of computers." style=cursor:pointer>Add Mesh</a>&nbsp'; }
r += '<a onclick=p10showMeshCmdDialog(0) style=cursor:pointer title="Download MeshCmd, a command line tool that performs many functions.">MeshCmd</a></div>';
r += '</div>';
QH('xdevices', r);
deviceHeaderSet();
// Re-check nodeid's
var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
for (var i in elements) { elements[i].checked = (checkedNodeids.indexOf(elements[i].value) >= 0); }
for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
p1updateInfo();
// Take care of KVM surfaces in desktop view mode
if (view == 3) {
var vsize = [{x:180,y:101}, {x:302,y:169}, {x:454,y:255}][Q('sizeselect').selectedIndex];
for (var i in multiDesktop) { multiDesktop[i].xxdelete = true; }
for (var i in kvmDivs) {
var id = kvmDivs[i], shortid = id.split('/')[2], desk = multiDesktop[id];
if (desk != null) {
// This device already has a canvas, use it.
desk.m.CanvasId.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
Q('xkvmid_' + shortid).appendChild(desk.m.CanvasId);
delete desk.xxdelete;
QH('skvmid_' + shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][((desk.m.State == null)?desk.m.state:desk.m.State)]);
} else {
var node = getNodeFromId(id);
if ((desktopNode == node) && (desktop != null)) { // Check if the main desktop is this device, if it is, use that.
// This device already has a canvas, use it.
var c = desktop.m.CanvasId;
c.setAttribute('id', 'kvmid_' + shortid);
c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
c.removeAttribute('onmousedown');
c.removeAttribute('onmouseup');
c.removeAttribute('onmousemove');
Q('xkvmid_' + shortid).appendChild(c);
QH('skvmid_' + shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][((desktop.m.State == null)?desktop.m.state:desktop.m.State)]);
if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
desktop.shortid = shortid;
desktop.onStateChanged = onMultiDesktopStateChange;
multiDesktop[id] = desktop;
desktop = desktopNode = currentNode = null;
// Setup a replacement desktop
QH('DeskParent', '<canvas id="Desk" width="640" height="200" style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
} else {
// This is a new device, create a canvas for it.
var c = document.createElement('canvas');
c.setAttribute('id', 'kvmid_' + shortid);
c.setAttribute('width', 640);
c.setAttribute('height', 200);
c.setAttribute('oncontextmenu', 'return false');
c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
try { Q('xkvmid_' + shortid).appendChild(c); } catch (ex) {}
// Check if we need to auto-connect
if (Q('autoConnectDesktopCheckbox').checked == true) { setTimeout(function() { connectMultiDesktop(node, 1); }, 100); }
}
}
}
for (var i in multiDesktop) {
// If a device is no longer viewed, disconnect it.
if (multiDesktop[i].xxdelete == true) { multiDesktop[i].Stop(); delete multiDesktop[i]; }
}
} else {
disconnectAllKvmFunction();
Q('autoConnectDesktopCheckbox').checked = false;
}
}
oldviewmode = view;
}
function toggleKvmDevice(nodeid) {
var node = getNodeFromId(nodeid), mesh = meshes[node.meshid], meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
if ((meshrights & 8) != 0) { // Requires remote control rights
//var conn = 0;
//if ((node.conn & 1) != 0) { conn = 1; } else if ((node.conn & 6) != 0) { conn = 2; } // Check what type of connect we can do (Agent vs AMT)
if (node.conn & 1) { connectMultiDesktop(node, 1); }
}
}
function autoConnectDesktops() { if (Q('autoConnectDesktopCheckbox').checked == true) { connectAllKvmFunction(); } }
function connectAllKvmFunction() { for (var i in nodes) { if (multiDesktop[nodes[i]._id] == null) { toggleKvmDevice(nodes[i]._id); } } }
function disconnectAllKvmFunction() { for (var nodeid in multiDesktop) { multiDesktop[nodeid].Stop(); } multiDesktop = {}; }
function onMultiDesktopStateChange(desk, state) { try { QH('skvmid_' + desk.shortid, ['Disconnected', 'Connecting...', 'Setup...', '', ''][state]); } catch (ex) {} }
function showMultiDesktopSettings() {
QV('d7amtkvm', false);
QV('d7meshkvm', true);
d7bitmapquality.value = multidesktopsettings.quality;
d7bitmapscaling.value = multidesktopsettings.scaling;
if (multidesktopsettings.framerate) { d7framelimiter.value = multidesktopsettings.framerate; } else { d7framelimiter.value = 1000; }
setDialogMode(7, "Remote Desktop Settings", 3, showMultiDesktopSettingsChanged);
}
function showMultiDesktopSettingsChanged() {
multidesktopsettings.quality = d7bitmapquality.value;
multidesktopsettings.scaling = d7bitmapscaling.value;
multidesktopsettings.framerate = d7framelimiter.value;
localStorage.setItem('multidesktopsettings', JSON.stringify(multidesktopsettings));
// Make changes to all current connections
for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
}
function connectMultiDesktop(node, contype) {
var nodeid = node._id, shortid = nodeid.split('/')[2];
var desk = multiDesktop[nodeid];
if (desk == null) {
if (Q('kvmid_' + shortid) == null) return; // Check if this device is being displayed, if not, exit now.
if (contype == 2) {
// Setup the Intel AMT remote desktop
if ((node.intelamt.user == null) || (node.intelamt.user == '')) { return; }
desk = CreateAmtRedirect(CreateAmtRemoteDesktop('kvmid_' + shortid));
desk.shortid = shortid;
//desk.debugmode = debugmode;
desk.onStateChanged = onMultiDesktopStateChange;
desk.m.bpp = 1;
desk.m.useZRLE = true;
desk.m.showmouse = true;
//desk.m.onScreenSizeChange = deskAdjust;
desk.Start(nodeid, 16994, '*', '*', 0);
desk.contype = 2;
multiDesktop[nodeid] = desk;
} else if (contype == 1) {
// Setup the Mesh Agent remote desktop
desk = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('kvmid_' + shortid), serverPublicNamePort);
desk.shortid = shortid;
desk.attemptWebRTC = attemptWebRTC;
desk.onStateChanged = onMultiDesktopStateChange;
desk.m.CompressionLevel = multidesktopsettings.quality;
desk.m.ScalingLevel = multidesktopsettings.scaling;
desk.m.FrameRateTimer = multidesktopsettings.framerate;
//desk.m.onDisplayinfo = deskDisplayInfo;
//desk.m.onScreenSizeChange = deskAdjust;
desk.Start(nodeid);
desk.contype = 1;
multiDesktop[nodeid] = desk;
}
} else {
// Disconnect and clean up the remote desktop
desk.Stop();
delete multiDesktop[nodeid];
}
}
function getMeshActions(mesh, meshrights) {
if ((meshrights & 4) == 0) return '';
var r = '';
if ((features & 2) == 0) { // If not LAN-Only
r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel&reg; AMT computer that is located on the internet." onclick=addCiraDeviceToMesh(\"' + mesh._id + '\")>Add CIRA</a>';
}
if (mesh.mtype == 1) {
if ((features & 1) == 0) { // If not WAN-Only
r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel&reg; AMT computer that is located on the local network." onclick=addDeviceToMesh(\"' + mesh._id + '\")>Add Local</a>';
r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel&reg; AMT computer by scanning the local network." onclick=addAmtScanToMesh(\"' + mesh._id + '\")>Scan Network</a>';
}
}
if (mesh.mtype == 2) {
r += ' <a style=cursor:pointer;font-size:10px title="Add a new computer to this mesh by installing the mesh agent." onclick=addAgentToMesh(\"' + mesh._id + '\")>Add Agent</a>';
if (features & 64) {
r += ' <a style=cursor:pointer;font-size:10px title="Invite someone to install the mesh agent." onclick=inviteAgentToMesh(\"' + mesh._id + '\")>Invite</a>';
}
}
return r;
}
function addDeviceToMesh(meshid) {
if (xxdialogMode) return;
var mesh = meshes[meshid];
var x = "Add a new Intel&reg; AMT device to mesh " + EscapeHtml(mesh.name) + ".<br /><br />";
x += addHtmlValue('Device Name', '<input id=dp1devicename style=width:230px maxlength=32 autocomplete=off onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
x += addHtmlValue('Hostname', '<input id=dp1hostname style=width:230px maxlength=32 autocomplete=off placeholder="Same as device name" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
x += addHtmlValue('Username', '<input id=dp1username style=width:230px maxlength=32 autocomplete=off placeholder="admin" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
x += addHtmlValue('Password', '<input id=dp1password type=password style=width:230px autocomplete=off maxlength=32 onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
x += addHtmlValue('Security', '<select id=dp1tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
setDialogMode(2, "Add Intel&reg; AMT device", 3, addDeviceToMeshEx, x, meshid);
validateDeviceToMesh();
Q('dp1devicename').focus();
}
// Display the Intel AMT scanning dialog box
function addAmtScanToMesh(meshid) {
if (xxdialogMode) return;
var x = "Enter a range of IP addresses to scan for Intel AMT devices.<br /><br />";
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>');
x += '<div id=dp1results style="width:100%;height:200px;background-color:white;border:1px gray solid;overflow-y:scroll"></div>';
setDialogMode(2, "Scan for Intel&reg; AMT devices", 3, addAmtScanToMeshEx, x, meshid);
QE('idx_dlgOkButton', false);
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>');
focusTextBox('dp1range');
}
function addAmtScanToMeshKeyUp(e) {
if (e.keyCode == 13) { haltEvent(e); addAmtScanToMeshButton(); }
}
// Called when OK is pressed on the Intel AMT scanning box
function addAmtScanToMeshEx(button, meshid) {
var elements = document.getElementsByClassName("DevScanCheckbox"), checkcount = 0;
for (var i in elements) {
if (elements[i].checked) {
var ipaddr = elements[i].getAttribute('tag');
var amtinfo = amtScanResults[ipaddr];
meshserver.send({ action: 'addamtdevice', meshid: meshid, devicename: ipaddr, hostname: amtinfo.hostname, amtusername: '', amtpassword: '', amttls: amtinfo.tls });
}
}
}
// If the user presses the "Scan" button on the Intel AMT scanning dialog box, start a scan.
function addAmtScanToMeshButton() {
QE('dp1range', false);
QE('dp1rangebutton', false);
QH('dp1results', '<div style=width:100%;text-align:center;margin-top:12px>Scanning...</div>');
meshserver.send({ action: 'scanamtdevice', range: Q('dp1range').value });
}
// Called when a scanned computer is checked or unchecked.
function addAmtScanToMeshCheckbox() {
var elements = document.getElementsByClassName("DevScanCheckbox"), checkcount = 0;
for (var i in elements) { if (elements[i].checked) checkcount++; }
QE('idx_dlgOkButton', checkcount > 0);
}
function addCiraDeviceToMesh(meshid) {
if (xxdialogMode) return;
var mesh = meshes[meshid];
// Replace non alphabetic characters (@ and $) with 'X' because MPS username cannot accept it.
var meshidx = meshid.split('/')[2].replace(/\@/g, 'X').replace(/\$/g, 'X');
var y = '<select id=dlgAddCiraSel onclick=dlgAddCiraSelClick() style=width:230px><option value=0>MeshCommander Script</option><option value=1>Manual Username/Password</option>';
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.
var x = '';
x += addHtmlValue('Setup Method', y);
x += '<hr>';
// Setup CIRA using a MeshCommander script (Pretty Simple)
x += "<div id=dlgAddCira0>To add a new Intel&reg; AMT device to mesh " + EscapeHtml(mesh.name) + " with CIRA, download the following script files and use <a href='http://meshcommander.com' target='_blank'>MeshCommander</a> to run the script to configure computers.<br /><br />";
x += addHtmlValue('Setup CIRA', '<a href="mescript.ashx?type=1&meshid=' + meshidx.substring(0, 16) + '" target="_blank">cira_setup.mescript</a>');
x += addHtmlValue('Cleanup CIRA', '<a href="mescript.ashx?type=2" target="_blank">cira_clean.mescript</a>');
x += "</div>";
// Setup CIRA with user/pass authentication (Somewhat difficult)
x += "<div id=dlgAddCira1 style=display:none>To add a new Intel&reg; AMT device to mesh " + EscapeHtml(mesh.name) + " with CIRA, load the following certificate as trusted root within Intel AMT";
if (serverinfo.mpspass) { x += " and authenticate to the server using this username and password.<br /><br />"; } else { x += " and authenticate to the server using this username and any password.<br /><br />"; }
x += addHtmlValue('Root Certificate', '<a href="MeshServerRootCert.cer" target="_blank">Root Certificate File</a>');
x += addHtmlValue('Username', '<input style=width:230px readonly value="' + meshidx.substring(0, 16) + '" />');
if (serverinfo.mpspass) { x += addHtmlValue('Password', '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpspass) + '" />'); }
if (serverinfo != null) { x += addHtmlValue('MPS Server', '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
x += "</div>";
// Setup CIRA with certificate authentication (Really difficult, only is allowed)
if ((features & 16) == 0) {
x += "<div id=dlgAddCira2 style=display:none>To add a new Intel&reg; AMT device to mesh " + EscapeHtml(mesh.name) + " with CIRA, load the following certificate as trusted root within Intel AMT, authenticate using a client certificate with the following common name and connect to the following server.<br /><br />";
x += addHtmlValue('Root Certificate', '<a href="MeshServerRootCert.cer" target="_blank">Root Certificate File</a>');
x += addHtmlValue('Organization', '<input style=width:230px readonly value="' + meshidx + '" />');
if (serverinfo != null) { x += addHtmlValue('MPS Server', '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
x += "</div>";
}
setDialogMode(2, "Add Intel&reg; AMT CIRA device", 1, null, x);
}
function dlgAddCiraSelClick() {
var val = Q('dlgAddCiraSel').value;
QV('dlgAddCira0', val == 0);
QV('dlgAddCira1', val == 1);
QV('dlgAddCira2', val == 2);
}
// Return true is the input string looks like an email address
function checkEmail(str) {
var x = str.split('@');
var ok = ((x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2));
if (ok == true) { var y = x[1].split('.'); for (var i in y) { if (y[i].length == 0) { ok = false; } } }
return ok;
}
function inviteAgentToMesh(meshid) {
if (xxdialogMode) return;
var mesh = meshes[meshid];
var x = "Invite someone to install the mesh agent. An email with be sent with the link to the mesh agent installation for " + EscapeHtml(mesh.name) + ".<br /><br />";
x += addHtmlValue('E-Mail', '<input id=agentInviteEmail style=width:240px onkeyup=validateAgentInvite()></input>');
setDialogMode(2, "Invite Mesh Agent", 3, performAgentInvite, x, meshid);
validateAgentInvite();
}
function validateAgentInvite() {
QE('idx_dlgOkButton', checkEmail(Q('agentInviteEmail').value));
}
function performAgentInvite(button, meshid) {
meshserver.send({ action: 'inviteAgent', meshid: meshid, email: Q('agentInviteEmail').value });
}
function addAgentToMesh(meshid) {
if (xxdialogMode) return;
var mesh = meshes[meshid], x = '';
x += addHtmlValue('Operating System', '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>Windows</option><option value=1>Linux</option><option value=2>Windows (UnInstall)</option><option value=3>Linux (UnInstall)</option></select>') + '<hr>';
// Windows agent install
//x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and configuration file and install the agent on the computer to manage.<br /><br />";
x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and install it the computer to manage. This agent has server and mesh information embedded within it.<br /><br />";
x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3&meshid=' + meshid.split('/')[2] + '" target="_blank" title="32bit version of the MeshAgent">Windows (.exe)</a>');
x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=4&meshid=' + meshid.split('/')[2] + '" target="_blank" title="64bit version of the MeshAgent">Windows x64 (.exe)</a>');
if (debugmode == true) { x += addHtmlValue('Settings File', '<a href="meshsettings?id=' + meshid.split('/')[2] + '" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>'); }
x += "</div>";
// Linux agent install
x += "<div id=agins_linux style=display:none>To add a computer to " + EscapeHtml(mesh.name) + " run the following command. Root credentails will be needed:<br />";
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>';
x += "</div>";
// Windows agent uninstall
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 />";
x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3" target="_blank" title="32bit version of the MeshAgent">Windows (.exe)</a>');
x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3" target="_blank" title="64bit version of the MeshAgent">Windows x64 (.exe)</a>');
x += "</div>";
// Linux agent uninstall
x += "<div id=agins_linux_un style=display:none>To remove a mesh agent, run the following command. Root credentails will be needed:<br />";
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>';
x += "</div>";
setDialogMode(2, "Add Mesh Agent", 9, null, x);
var servername = serverinfo.name;
if ((servername == 'un-configured') || ((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.
if (serverinfo.https == true) {
var portStr = (serverinfo.port == 443)?'':(":" + serverinfo.port);
Q('agins_linux_area').value = "wget -q https://" + servername + portStr + "/meshagents?script=1 --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://" + servername + portStr + " '" + meshid.split('/')[2] + "'\r\n";
Q('agins_linux_area_un').value = "wget -q https://" + servername + portStr + "/meshagents?script=1 --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
} else {
var portStr = (serverinfo.port == 80)?'':(":" + serverinfo.port);
Q('agins_linux_area').value = "wget -q http://" + servername + portStr + "/meshagents?script=1 -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh http://" + servername + portStr + " '" + meshid.split('/')[2] + "'\r\n";
Q('agins_linux_area_un').value = "wget -q http://" + servername + portStr + "/meshagents?script=1 -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
}
Q('aginsSelect').focus();
}
function addAgentToMeshClick() {
var v = Q('aginsSelect').value;
QV('agins_windows', v == 0);
QV('agins_linux', v == 1);
QV('agins_windows_un', v == 2);
QV('agins_linux_un', v == 3);
}
function validateDeviceToMesh() {
QE('idx_dlgOkButton', (Q('dp1devicename').value.length > 0) && (passwordcheck(Q('dp1password').value)));
}
function addDeviceToMeshEx(button, meshid) {
var amtuser = Q('dp1username').value;
if (amtuser == '') amtuser = 'admin';
var host = Q('dp1hostname').value;
if (host == '') host = Q('dp1devicename').value;
meshserver.send({ action: 'addamtdevice', meshid: meshid, devicename: Q('dp1devicename').value, hostname: host, amtusername: amtuser, amtpassword: Q('dp1password').value, amttls: Q('dp1tls').value });
}
function deviceHeaderSet() {
if (deviceHeaderId == 0) { deviceHeaderId = 1; return; }
deviceHeaders["DevxHeader" + deviceHeaderId] = ', ' + deviceHeaderTotal + ((deviceHeaderTotal == 1) ? ' node' : ' nodes');
var title = '';
for (x in deviceHeaderCount) { if (title.length > 0) title += ', '; title += deviceHeaderCount[x] + ' ' + PowerStateStr2(x); }
deviceHeadersTitles["DevxHeader" + deviceHeaderId] = title;
deviceHeaderId++;
deviceHeaderCount = {};
deviceHeaderTotal = 0;
}
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>'];
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'];
var powerColorTable = ['#00000000', 'black', 'blue', 'blue', 'lightblue', 'blueviolet', 'darkgreen', 'lightseagreen', 'lightseagreen'];
function NodeStateStr(node) {
var states = [];
if (node.state > 0 && node.state < powerStatetable.length) state.push(powerStatetable[node.state]);
if (node.conn) {
if ((node.conn & 1) != 0) states.push('<span title="Mesh agent is connected and ready for use.">Agent</span>');
if ((node.conn & 2) != 0) states.push('<span title="Intel&reg; AMT CIRA is connected and ready for use.">CIRA</span>');
if ((node.conn & 4) != 0) states.push('<span title="Intel&reg; AMT is routable.">Intel&reg; AMT</span>');
if ((node.conn & 8) != 0) states.push('<span title="Mesh agent is reachable using another agent as relay.">Relay</span>');
}
if ((node.pwr != null) && (node.pwr != 0)) { states.push(powerStateStrings[node.pwr]); }
return states.join(', ');
}
function PowerStateStr(x) {
if (x < powerStatetable.length) return powerStatetable[x];
return '';
}
function PowerStateStr2(x) {
if ((x != 0) && (x < powerStatetable.length)) return powerStatetable[x];
return 'Unknown';
}
function selectallButtonFunction() {
var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
for (var i in elements) { if (elements[i].checked) checkcount++; }
for (var i in elements) { elements[i].checked = (checkcount == 0); }
p1updateInfo();
}
function p1updateInfo() {
var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
for (var i in elements) { if (elements[i].checked) checkcount++; }
if (checkcount > 0) {
QE('GroupActionButton', true);
Q('SelectAllButton').value = 'Select None';
QV('cxmgroupsplit', true);
QV('cxmdesktop', true);
} else {
QE('GroupActionButton', false);
Q('SelectAllButton').value = 'Select All';
QV('cxmgroupsplit', false);
QV('cxmdesktop', false);
}
}
function groupActionFunction() {
var x = "Select an operation to perform on all selected devices. Actions will be performed only with proper rights.<br /><br />";
x += addHtmlValue('Operation', '<select id=d2groupop style=float:right;width:250px><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=101>Delete devices</option></select>');
setDialogMode(2, "Group Action", 3, groupActionFunctionEx, x);
}
// Get the list of checked devices, removes any duplicates.
function getCheckedDevices() {
var nodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
for (var i in elements) { if (elements[i].checked) { if (elements[i].value) { var nid = elements[i].value.substring(6); if (nodeids.indexOf(nid) == -1) { nodeids.push(nid); } } } }
return nodeids;
}
function groupActionFunctionEx() {
var op = Q('d2groupop').value;
if (op == 100) {
// Group wake
meshserver.send({ action: 'wakedevices', nodeids: getCheckedDevices() });
} else if (op == 101) {
// Group delete, ask for confirmation
var x = "Confirm delete selected devices(s)?<br /><br />";
x += "<input id=d2check type=checkbox onchange=d2groupActionFunctionDelEx() />Confirm";
setDialogMode(2, "Delete Nodes", 3, groupActionFunctionDelEx, x);
QE('idx_dlgOkButton', false);
} else {
// Power operation
meshserver.send({ action: 'poweraction', nodeids: getCheckedDevices(), actiontype: op });
}
}
function d2groupActionFunctionDelEx() { QE('idx_dlgOkButton', Q('d2check').checked); }
function groupActionFunctionDelEx() { meshserver.send({ action: 'removedevices', nodeids: getCheckedDevices() }); }
function onSortSelectChange(skipsave) {
sort = document.getElementById("sortselect").selectedIndex;
if (!skipsave) { putstore("sort", sort); }
if (sort == 0) { nodes.sort(meshSort); }
if (sort == 1) { nodes.sort(powerSort); }
if (sort == 2) { if (showHostnames == true) { nodes.sort(deviceHostSort); } else { nodes.sort(deviceSort); } }
updateDevices();
}
function meshSort(a, b) { if (a.meshnamel > b.meshnamel) return 1; if (a.meshnamel < b.meshnamel) return -1; if (a.meshid == b.meshid) { if (showHostnames == true) { if (a.hostl > b.hostl) return 1; if (a.hostl < b.hostl) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } return 0; }
function powerSort(a, b) { var ap = a.pwr?a.pwr:0; var bp = b.pwr?b.pwr:0; if (ap == bp) { if (showHostnames == true) { if (a.hostl > b.hostl) return 1; if (a.hostl < b.hostl) 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; }
function deviceSort(a, b) { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; }
function deviceHostSort(a, b) { if (a.hostl > b.hostl) return 1; if (a.hostl < b.hostl) return -1; return 0; }
function onSearchInputChanged() { var x = Q('SearchInput').value.toLowerCase(); putstore("search", x); if (x == '') { for (var d in nodes) { nodes[d].v = true; } } else { for (var d in nodes) { nodes[d].v = (nodes[d].name.toLowerCase().indexOf(x) >= 0) || (nodes[d].hostl != null && nodes[d].hostl.toLowerCase().indexOf(x) >= 0); } } updateDevices(); }
function onSearchFocus(x) { searchFocus = x; }
function onMapSearchFocus(x) { mapSearchFocus = x; }
function onConsoleFocus(x) { consoleFocus = x; }
var contextelement = null;
function handleContextMenu(event) {
hideContextMenu();
var scrollLeft = (window.pageXOffset !== null) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
var scrollTop = (window.pageYOffset !== null) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
var elem = document.elementFromPoint(event.pageX - scrollLeft, event.pageY - scrollTop);
if (elem && elem != null && elem.id == "MxMESH") {
contextelement = elem;
var contextmenudiv = document.getElementById("meshContextMenu");
contextmenudiv.style.left = event.pageX + "px";
contextmenudiv.style.top = event.pageY + "px";
contextmenudiv.style.display = "block";
} else {
while (elem && elem != null && elem.id != "devs") { elem = elem.parentElement; }
if (!elem || elem == null) return true;
contextelement = elem;
var contextmenudiv = document.getElementById("contextMenu");
contextmenudiv.style.left = event.pageX + "px";
contextmenudiv.style.top = event.pageY + "px";
contextmenudiv.style.display = "block";
}
return haltEvent(event);
}
function cmaction(action) {
var nodeid = contextelement.children[1].attributes.onclick.value;
nodeid = nodeid.substring(12, nodeid.length - 2);
if (action == 1) gotoDevice(nodeid, 10); // General
if (action == 2) gotoDevice(nodeid, 12); // Desktop
if (action == 3) gotoDevice(nodeid, 11); // Terminal
if (action == 4) gotoDevice(nodeid, 13); // Files
if (action == 5) gotoDevice(nodeid, 16); // Events
if (action == 6) gotoDevice(nodeid, 15); // Console
if (action == 7) { Q('viewselect').value = 3; Q('viewselect').onchange(); Q('autoConnectDesktopCheckbox').checked = true; Q('autoConnectDesktopCheckbox').onclick(); } // Multi-Desktop
}
function cmmeshaction(action) {
var meshid = contextelement.attributes.onclick.value.substring(32, (32 + 69));
var elements = document.getElementsByClassName("DeviceCheckbox");
if (action == 1) { for (var i in elements) { if (elements[i].attributes && elements[i].attributes.class.value.substring(0, 69) == meshid) { elements[i].checked = true; } } }
if (action == 2) { for (var i in elements) { if (elements[i].attributes && elements[i].attributes.class.value.substring(0, 69) == meshid) { elements[i].checked = false; } } }
//if (action == 3) { window.location = "multidesktop.aspx?mesh=" + meshid + "&auto=1"; }
p1updateInfo();
}
function hideContextMenu() {
QV('contextMenu', false);
QV('meshContextMenu', false);
contextelement = null;
}
//
// DEVICES MAP
//
// Maps code starts from here. Initialize all the variables
var xxmap = {
map: null,
contextmenu: null,
activeInteractions: [], // Save Modified features in this list
showindex: 0,
markersSource: null, // Initialize a Source Vector
markersLayer: null,
mapLayer: null, // Create a tile and use OSM source
mapView: null, // Sets the initial view
}
// Add a feature for every Node and change style if connection status changes
function updateMapMarkers(selectedMesh) {
if ((xxmap != null) && (xxmap.map == null)) loadmap();
if (xxmap == null) return;
var boundingBox = null;
for (var i in nodes) {
var loc = map_parseNodeLoc(nodes[i]);
var feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
if ((loc != null) && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
lat = loc[0];
lon = loc[1];
var type = loc[2];
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; } }
if (feature == null) { addFeature(nodes[i]); boundingBox[4] = 1; } else { updateFeature(nodes[i], feature); feature.setStyle(markerStyle(nodes[i], loc[2])); } // Update Feature
} else {
if (feature) { xxmap.markersSource.removeFeature(feature); }
}
}
return boundingBox;
}
// Show node details on hovering over a feature
var map_cm_popup = new ol.Overlay({ element: Q('xmap-info-window'), positioning: 'bottom-center', stopEvent: false });
// Edit Marker item
var map_cm_editMarker = { text: "Modify node location", callback: function (obj) { modifyMarkerloc(obj.data); } };
// Clear Marker item
var map_cm_clearMarker = { text: "Remove node location", callback: function (obj) {
meshserver.send({ action: 'changedevice', nodeid: obj.data.a, userloc: [] }); // Clear the user position marker
}};
// Save Marker item
var map_cm_saveMarker = { text: "Save node location", callback: function (obj) { saveMarkerloc(obj.data); } };
// Build a context menu for a feature
var map_cm_nodemenu_items = [
{ text: "General information", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 10); } } },
{ text: "Desktop", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 11); } } },
{ text: "Terminal", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 12); } } },
{ text: "Intel&reg; AMT", callback: function (obj) { if (obj.data !=null) { gotoDevice(obj.data, 14); } } },
'-',
{ text: 'Zoom-in to extent', callback: function(obj) { var coords = obj.data.getGeometry().getCoordinates(); zoomToLocation(coords, 19); } },
{ text: 'Zoom-out to extent', callback: function(obj) { var coords = obj.data.getGeometry().getCoordinates(); zoomToLocation(coords, 2); } }
];
// Context menu for clicks other than on feature
var contextmenu_items = [
{ text: 'Refresh', callback: function () { refreshMap(true, true); } },
{ text: 'Zoom to fit extent', callback: function () { zoomToFitExtent(); } },
{ text: 'Center map here', callback: function(obj) { xxmap.mapView.animate({ center: obj.coordinate } ); } },
{ text: 'Place node here', callback: function(obj) { placeNode(obj.coordinate); } }
];
function stringToIntHash(str) {
var hash = 0, i;
for (i = 0; i < str.length; i++) { hash = ((hash << 5) - hash) + str.charCodeAt(i); hash |= 0; }
return hash;
};
// Get the lat/lon from a node
function map_parseNodeLoc(node) {
var loc = null, t = 0;
if (node.iploc) { loc = node.iploc; t = 1; }
if (node.wifiloc) { loc = node.wifiloc; t = 2; }
if (node.gpsloc) { loc = node.gpsloc; t = 3; }
if (node.userloc) { loc = node.userloc; t = 4; }
if ((loc == null) || (typeof loc != 'string')) return;
loc = loc.split(',');
if (t == 1) {
// If this is IP location, randomize the position a little.
return [ parseFloat(loc[0]) + (stringToIntHash(node._id.substring(0, 20)) / 100000000000), parseFloat(loc[1]) + (stringToIntHash(node._id.substring(20)) / 100000000000), t ];
} else {
// Return the real position
return [ parseFloat(loc[0]), parseFloat(loc[1]), t ];
}
}
// Load the entire map
function loadmap() {
if (xxmap == null) return;
try {
// Initialize a Source Vector
xxmap.markersSource = new ol.source.Vector();
xxmap.markersLayer = new ol.layer.Vector({
source: xxmap.markersSource
});
// Create a tile and use OSM source
xxmap.mapLayer = new ol.layer.Tile({ source: new ol.source.OSM() });
xxmap.mapView = new ol.View({ // Set the initial view
center: ol.proj.transform([0, 0], 'EPSG:4326', 'EPSG:3857'),
zoom: 2,
minZoom: 2,
maxZoom: 20,
extent: ol.proj.transformExtent([-100000, -69.55, 100000, 69.55], 'EPSG:4326', 'EPSG:3857')
});
xxmap.map = new ol.Map({
target: 'xdevicesmap',
layers: [xxmap.mapLayer, xxmap.markersLayer],
view: xxmap.mapView
});
xxmap.map.addOverlay(map_cm_popup);
// Goto information tab if a user clicks on a feature
xxmap.map.on('click', function(evt) {
var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(feat, layer) { return feat; });
if (feature) {
var nodeid = feature.getId();
if (nodeid != null) { gotoDevice(nodeid, 10); } // Goto general info tab
else { // For pointer
var nodeFeatgoto = getCorrespondingFeature(feature); gotoDevice(nodeFeatgoto.getId(), 10);
}
}
});
// On hover feature show the name of the node. Also add pointer style
xxmap.map.on('pointermove', function(evt) {
var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(feat, layer) { return feat; });
if (feature) {
xxmap.map.getTargetElement().style.cursor = 'pointer';
var coord = feature.getGeometry().getCoordinates();
// map_cm_popup.setPosition(evt.coordinate);
map_cm_popup.setPosition(coord);
featid = feature.getId();
if (featid) {
QH('xmap-info-window', feature.get('name'));
} else {
var nodeFeat = getCorrespondingFeature(feature); // Return the node feature associated to pointer.
QH('xmap-info-window', nodeFeat.get('name'));
}
} else {
xxmap.map.getTargetElement().style.cursor = '';
QH('xmap-info-window', '');
}
});
// Initialize context menu for openlayers
contextmenu = new ContextMenu({
width: 160,
defaultItems: false, // defaultItems are Zoom In/Zoom Out
items: contextmenu_items
});
// On right click open the context menu
contextmenu.on("open", function (evt) {
var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(ft, l){ return ft; });
xxmap.contextmenu.clear(); //Clear the context menu
if (feature) {
var featId = feature.getId();
if (featId) { addContextMenuItems(feature); } // Node feature will have an id
else { // If the feature is a pointer, Get its corresponding Node feature
var nodeFeature = getCorrespondingFeature(feature); //return the node feature associated to pointer.
if (nodeFeature) { addContextMenuItems(nodeFeature); }
else{ xxmap.contextmenu.extend(contextmenu_items); }
}
}
else { xxmap.contextmenu.extend(contextmenu_items); }
});
if (xxmap.contextmenu == null) { xxmap.contextmenu = contextmenu; }
xxmap.map.addControl(xxmap.contextmenu);
//addMeshOptions(); // Adds Mesh names to mesh dropdown
} catch (e) {
QV('viewselectmapoption', false);
xxmap = null;
}
}
// Add feature on to Map for a Node
function addFeature(node, lat, lon) {
var existingfeature = getModifiedFeature(node._id); // Check if Corresponding feature was Modified ( Modifed feature are in active interactions list)
if (existingfeature) { xxmap.markersSource.addFeature(existingfeature); } // Add that existing feature
else { // Add new feature for this node
if (!lat && !lon) { var loc = map_parseNodeLoc(node); lat = loc[0]; lon = loc[1]; }
// 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.
if (lon > 180) { lon = 180 - lon; meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: [ lat, lon ] }); }
if ((lat < 90) && (lat > -90) && (lon < 180) && (lon > -180)) { // Check valid lat/lon
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 });
feature.setId(node._id); // Set id for the device as nodeid
feature.setStyle(markerStyle(node));
xxmap.markersSource.addFeature(feature); // Add the feature to Marker Source
}
}
}
// Removing any feature from map
function removeFeature(node) {
var feature = xxmap.markersSource.getFeatureById(node._id);
if (feature) { xxmap.markersSource.removeFeature(feature); }
}
// Update feature
function updateFeature(node, feature) {
if (node.conn != feature.get('status') ) { // Update status if changed
feature.set('status',node.conn)
feature.setStyle(markerStyle(node));
}
// Since this is IP address location, add some fixed randomness to the location. Avoid pin pile-up.
var loc = map_parseNodeLoc(node); lat = loc[0]; lon = loc[1];
if ((lat != feature.get('lat')) || (lon != feature.get('lon'))) { // Update lat and lon if changed
feature.set('lat', lat); feature.set('lon', lon);
var modifiedCoordinates = ol.proj.transform([parseFloat(lon), parseFloat(lat)], 'EPSG:4326','EPSG:3857');
feature.getGeometry().setCoordinates(modifiedCoordinates);
}
if (node.name != feature.get('name') ) { feature.set('name', node.name); } // Update name
}
// Enable dragging of a marker after edit option is clicked in context menu
function modifyMarkerloc(ft){
var featid = ft.getId();
if (featid) {
ft.setStyle(markerStyle(getNodeFromId(ft.a), 4)); // Switch to a user marker
if ( !getActiveInteractions(ft)) {
var dragInteration = new ol.interaction.Modify({
features: new ol.Collection([ft]),
pixelTolerance: 10
});
xxmap.activeInteractions.push({ featureid: featid, feature:ft, interaction: dragInteration }); // Also keep track of Interactions
xxmap.map.addInteraction(dragInteration);
}
}
}
// This will be called when save location option is clicked in context menu
function saveMarkerloc(ft){
var featid = ft.getId()
if (featid) {
var actInteraction = getActiveInteractions(ft);
if (actInteraction) { // Check if the interaction exists
xxmap.map.removeInteraction(actInteraction); //Clear Interaction for that node
removeInteraction(featid);
var coord = ft.getGeometry().getCoordinates();
var v = ol.proj.transform(coord, 'EPSG:3857', 'EPSG:4326');
if (v[0] > 180) { v[0] = 180 - v[0]; }
var vx = [ v[1], v[0] ]; // Flip the coordinates around, lat/long
meshserver.send({ action: 'changedevice', nodeid: featid, userloc: vx }); // Send them to server to save changes
}
}
}
// Style the Markers
function markerStyle(node, type) {
if (type == null) {
type = 0;
if (node.iploc) { type = 1; }
if (node.wifiloc) { type = 2; }
if (node.gpsloc) { type = 3; }
if (node.userloc) { type = 4; }
}
var types = ['', '-ip','-wifi','-gps','-user'];
var color = connStateColor(node);
var style = new ol.style.Style({
image: new ol.style.Icon({ color: color, anchor: [0.5, 1], src: 'images/mapmarker' + types[type] + '.png' })
//stroke: new ol.style.Stroke({ color: '#000', width: 20 })
//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 }) })
});
/*
deviceMark.setStyle(new ol.style.Style({
text: new ol.style.Text({
//font: '12px helvetica,sans-serif',
text: currentNode.name,
textAlign: 'right',
offsetX: -10,
fill: new ol.style.Fill({ color: '#000' }),
stroke: new ol.style.Stroke({ color: '#fff', width: 2 })
}),
image: new ol.style.Icon(({ color: [113, 140, 0], src: 'images/dot.png' })) }));
*/
return [ style ];
}
// TODO: Add more connection status types. Currently we only change color if connection status changes
function connStateColor(nodeConn){
if (nodeConn.conn == 1 || nodeConn.conn == 5) { return '#00ffdd'; } // Green for connected devices
return '#C70039'; // Red if the Agent is not connected
}
// Add save/edit option to context menu
function addContextMenuItems(feature) {
if (getActiveInteractions(feature)) { // If this feature is modified then display save option in contextmenu
map_cm_saveMarker.data = feature;
xxmap.contextmenu.push(map_cm_saveMarker);
} else {
map_cm_editMarker.data = feature;
xxmap.contextmenu.push(map_cm_editMarker);
var node = getNodeFromId(feature.a);
if (node.userloc) {
map_cm_clearMarker.data = feature;
xxmap.contextmenu.push(map_cm_clearMarker);
}
}
map_cm_nodemenu_items.forEach(function (item){
if (item.text == 'Zoom-in to extent' || item.text == 'Zoom-out to extent') { item.data = feature; }
else { item.data = feature.getId(); }
});
xxmap.contextmenu.extend(map_cm_nodemenu_items);
}
// Return a active Interaction if it exists in activeInteractions list
function getActiveInteractions(feature) {
var featid = feature.getId();
for (var i = 0; i < xxmap.activeInteractions.length; i++) {
if (xxmap.activeInteractions[i].featureid == featid) { return xxmap.activeInteractions[i].interaction; }
}
return false;
}
// Return Modified feature based on Id
function getModifiedFeature(featid) {
if (featid) {
for (var i = 0; i < xxmap.activeInteractions.length; i++) {
if (xxmap.activeInteractions[i].featureid == featid) { return xxmap.activeInteractions[i].feature; }
}
}
return null;
}
// Remove Interaction
function removeInteraction(ftid) {
var index = -1;
for (var i = 0; i < xxmap.activeInteractions.length; i++) {
if (xxmap.activeInteractions[i].featureid === ftid) { index = i; break; }
}
if (index >= 0) { xxmap.activeInteractions.splice(index, 1); }
}
// Check if pointer coordinates are equal to features and return node feature
function getCorrespondingFeature(pointerFeat) {
var pointerCoord = pointerFeat.getGeometry().getCoordinates();
for (var i = 0; i < xxmap.activeInteractions.length ; i++) {
var modifiedFeatures = xxmap.activeInteractions[i].feature;
var fearCoord = modifiedFeatures.getGeometry().getCoordinates();
if (fearCoord[0].toFixed(5) == pointerCoord[0].toFixed(5) && fearCoord[1].toFixed(5) == pointerCoord[1].toFixed(5) ) { return modifiedFeatures; }
}
return null;
}
// Refresh the map and clear list
function refreshMap(reset, rebound){
if (reset) {
xxmap.map.setTarget(null);
xxmap.map = null;
xxmap.markersSource = null;
xxmap.mapView = null;
xxmap.mapLayer = null;
xxmap.activeInteractions = []; // Clear Active Interaction list
}
//clearMeshOptions();
//onSelectMeshChange();
var box = updateMapMarkers();
if ((box != null) && (rebound || (box[4] == 1))) {
var clat = (box[0] + box[2]) / 2;
var clon = (box[1] + box[3]) / 2;
var cscale = Math.max(Math.abs(box[0] - box[2]), Math.abs(box[1] - box[3]));
var view = xxmap.map.getView();
view.setCenter(ol.proj.transform([clon, clat], 'EPSG:4326', 'EPSG:3857'));
var i = 360, j = -2;
while (i > cscale) { j++; i = i / 2; }
view.setZoom(j);
}
}
// Called When Place a node option is clicked from context menu
function placeNode(coords) {
if (xxdialogMode) return;
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>';
for (var i in nodes) {
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 />';
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>';
}
setDialogMode(2, "Select a node to place", 3, placeNodeEx, x + '</div>', coords);
onPlaceNodeInputChange();
}
function placeNodeEx(button, coords) {
var elements = document.getElementsByName("PlaceMapDeviceCheckbox");
for (var i in elements) {
if (elements[i].checked) {
var node = getNodeFromId(elements[i].id.substring(0, elements[i].id.length - 8));
if (node) {
var feature = xxmap.markersSource.getFeatureById(i);
var v = ol.proj.transform(coords, 'EPSG:3857', 'EPSG:4326');
var vx = [ v[1], v[0] ]; // Flip the coordinates around, lat/long
if (feature) {
feature.getGeometry().setCoordinates(coords);
var activeInteraction = getActiveInteractions(feature);
if (activeInteraction) {
saveMarkerloc(feature);
} else { // If this feature is not saved after its location is changed, then send updated coords to server.
meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: vx }); // Send them to server to save changes
}
} else {
meshserver.send({ action: 'changedevice', nodeid: node._id, userloc: vx }); // This Node is not yet added to maps.
}
}
}
}
}
// Called when the user changes the search box
function onPlaceNodeInputChange() {
updatePlaceNodeTable(Q('selectnode-search').value.trim().toLowerCase());
}
// Update the list of devices in the "place on map" table
function updatePlaceNodeTable(inputSearch) {
var elements = document.getElementsByName("PlaceMapDeviceCheckbox"), count = 0;
for (var i in nodes) {
var visible = ((nodes[i].namel.indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].hostl != null && nodes[i].hostl.indexOf(inputSearch) >= 0));
if (visible) { count++; }
QV(nodes[i]._id + '-rowid', visible);
}
QV('noNodesMapPlace', count == 0);
/*
console.log(selected);
for (var i in nodes) {
if ((nodes[i].name.toLowerCase().indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].hostl != null && nodes[i].hostl.toLowerCase().indexOf(inputSearch) >= 0)) {
console.log(selected.indexOf(nodes[i]._id));
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':'') + ' />';
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>';
}
}
if (x == '') { x = '<div style=text-align:center;width:100%>No devices found.</div>'; }
QH('placenode', '');
*/
}
// Called when a user clicks on a device to toggle selection for placement on map.
function selectNodeToPlace(e, id) {
// Toggle checkbox if needed
if (e.target.name != 'PlaceMapDeviceCheckbox') { var inputElement = Q(id + '-checkid'); inputElement.checked = !inputElement.checked; }
// Check button state
var elements = document.getElementsByName("PlaceMapDeviceCheckbox"), checkcount = 0;
for (var i in elements) { if (elements[i].checked) checkcount++; }
QE('idx_dlgOkButton', checkcount > 0);
}
// Add option for available meshes in mesh Dropdown
function addMeshOptions(addMeshid, meshName) {
/*
var meshOptions = Q('select-mesh');
if (addMeshid && meshName) {
var option = document.createElement('option');
option.value =addMeshid;
option.text = meshName;
meshOptions.add(option); // Add specific option
}
else {
for (var i in meshes) { // Add all options
var option = document.createElement('option');
option.value = i;
option.text = meshes[i].name;
meshOptions.add(option);
}
}
*/
}
// Remove/Modify options in Mesh dropdown (if modMeshname is defined then Modify else Remove)
function meshOptionRmvMod(delMeshid, modMeshname){
/*
var meshOptions = Q('select-mesh');
if (delMeshid) {
var index=-1;
for (var i = 1; i < meshOptions.options.length; i++) {
if (meshOptions[i].value === delMeshid) { index=i; }
}
if (index > 0) {
if (modMeshname) {
meshOptions[index].innerHTML=modMeshname; // If Mesh name is Modified
}
else { meshOptions.remove(index); }
}
}
*/
}
//Check if there is any mesh created
function meshExists() {
for (var i in meshes) { if (meshes[i]) { return true; } }
return false;
}
// Reset Mesh dropdown option to 'All' when a current view mesh is deleted.
function setMeshView(emeshid) {
var selectMeshElement=Q("select-mesh");
var selectedIndex = selectMeshElement.selectedIndex;
if (selectMeshElement[selectedIndex].value == emeshid) { selectMeshElement[0].selected = true; onSelectMeshChange(); }
}
// Clear all mesh options except 'All'
function clearMeshOptions() {
/*
var meshOptions=Q('select-mesh');
for(var i = meshOptions.options.length - 1 ; i > 0 ; i--) { meshOptions.remove(i); }
*/
}
// Make a http get call- Replace this with AJAX get if jquery is used
function getSearchLocation() {
try {
var searchdata = Q('mapSearchLocation').value.trim();
if (searchdata.length > 0) {
var xmlhttp = new XMLHttpRequest(); // Compatible with Chrome, Opera, Safari, IE7+, Firefox.
xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { formatSearchData(xmlhttp.responseText); } }
xmlhttp.open("GET", 'https://nominatim.openstreetmap.org/search?q=' + searchdata + '&format=json', true); // Get request
xmlhttp.send();
}
} catch (e) {}
}
// Format data recieved from nominatim API and display it on content window
function formatSearchData(data) {
try {
QH('xmapSearchResults','');
var dataInfo = JSON.parse(data), count = 0, x = '<div style="overflow-y:auto;width:100%;max-height:240px">';
for (var i = 0; i < dataInfo.length; i++) {
if (dataInfo[i].display_name && dataInfo[i].boundingbox[0] && dataInfo[i].boundingbox[1] && dataInfo[i].boundingbox[2] && dataInfo[i].boundingbox[3]) {
count++;
var color = (i % 2 == 0)?'F5F5F5':'EBEBEB';
x += '<div style=cursor:pointer;padding:5px;background-color:#' + color + ' 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>';
}
}
x += '</div>';
if (count == 1) {
// If only one result is returned then zoom to that location
var extent = [ parseFloat(dataInfo[0].boundingbox[2]), parseFloat(dataInfo[0].boundingbox[0]), parseFloat(dataInfo[0].boundingbox[3]), parseFloat(dataInfo[0].boundingbox[1]) ];
zoomToExtent(extent);
} else {
if (count == 0) { x = '<div style=width:200px>No location found.<div>'; }
QV('xmapSearchResultsDlg', true);
}
QH('xmapSearchResults', x);
}
catch (e) {}
}
// Zoom into the bounding box
function mapGotoSelectedLocation(obj) {
var objchildren = obj.children;
var boundingBox = objchildren[1].innerHTML.split('!#!');
var extent = [parseFloat(boundingBox[2]), parseFloat(boundingBox[0]), parseFloat(boundingBox[3]), parseFloat(boundingBox[1])];
//Q('search-location').value = objchildren[0].innerHTML;
zoomToExtent(extent);
mapCloseSearchWindow();
}
// Close the search window
function mapCloseSearchWindow() {
QH('xmapSearchResults', '');
QV('xmapSearchResultsDlg', false);
}
// Zoom to specific cordinates
function zoomToLocation(coordinates, zoomVal) {
var view = xxmap.map.getView();
view.setCenter(coordinates);
view.setZoom(zoomVal);
}
function zoomToFitExtent() {
var features = xxmap.markersSource.getFeatures();
if (features.length > 0) {
var extent = xxmap.markersSource.getExtent();
xxmap.map.getView().fit(extent, xxmap.map.getSize());
}
}
function zoomToExtent(extent){
var boundingExtent = ol.proj.transformExtent(extent, ol.proj.get('EPSG:4326'), ol.proj.get('EPSG:3857'));
xxmap.map.getView().fit(boundingExtent, xxmap.map.getSize());
}
//
// MY DEVICE
//
function refreshDevice(nodeid) {
if (!currentNode || currentNode._id != nodeid) return;
gotoDevice(nodeid, xxcurrentView, true);
}
function getNodeRights(nodeid) {
var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
return mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
}
var currentNode;
var powerTimelineNode = null;
var powerTimelineReq = null;
var powerTimelineUpdate = null;
var powerTimeline = null;
function getCurrentNode() { return currentNode; };
function gotoDevice(nodeid, panel, refresh) {
//disconnectAllKvmFunction();
var node = getNodeFromId(nodeid);
var mesh = meshes[node.meshid];
var meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
if (!currentNode || currentNode._id != node._id || refresh == true) {
currentNode = node;
// Add node name
var nname = EscapeHtml(node.name);
if (nname.length == 0) { nname = '<i>None</i>'; }
if ((meshrights & 4) != 0) { nname = '<span onclick=showEditNodeValueDialog(0) style=cursor:pointer>' + nname + '</span>'; }
QH('p10deviceName', nname);
QH('p11deviceName', nname);
QH('p12deviceName', nname);
QH('p13deviceName', nname);
QH('p14deviceName', nname);
QH('p15deviceName', nname);
QH('p16deviceName', nname);
// Node attributes
var x = '<table style=width:100%>';
// Attribute: Mesh
x += addDeviceAttribute('Mesh', '<a onclick=gotoMesh("' + node.meshid + '") style=cursor:pointer>' + EscapeHtml(meshes[node.meshid].name) + '</a>');
// Attribute: Host
if ((mesh.mtype == 1) || (node.name != node.host)) {
if ((meshrights & 4) != 0) {
if (node.host) {
x += addDeviceAttribute('Hostname', '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer>' + EscapeHtml(node.host) + '</span>');
} else {
x += addDeviceAttribute('Hostname', '<span onclick=showEditNodeValueDialog(1) style=cursor:pointer><i>None</i></span>');
}
} else {
x += addDeviceAttribute('Hostname', EscapeHtml(node.host));
}
}
// Attribute: Description
var description = node.desc?EscapeHtml(node.desc):"<i>None</i>";
if ((meshrights & 4) != 0) {
x += addDeviceAttribute('Description', '<span onclick=showEditNodeValueDialog(2) style=cursor:pointer>' + description + '</span>');
} else {
x += addDeviceAttribute('Description', description);
}
// Attribute: Mesh Agent
var agentsStr = ['Unknown', 'Windows 32bit console', 'Windows 64bit console', 'Windows 32bit service', 'Windows 64bit service', 'Linux 32bit', 'Linux 64bit', 'MIPS', 'XENx86', 'Android ARM', 'Linux ARM', 'OSX 32bit', 'Android x86', 'PogoPlug ARM', 'Android APK', 'Linux Poky x86-32bit', 'OSX 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' ];
if ((node.agent != null) && (node.agent.id != null) && (node.agent.ver != null)) {
var str = '';
if (node.agent.id <= agentsStr.length) { str = agentsStr[node.agent.id]; } else { str = agentsStr[0]; }
if (node.agent.ver != 0) { str += ' v' + node.agent.ver; }
x += addDeviceAttribute('Mesh Agent', str);
}
// Attribute: Intel AMT
if (node.intelamt != null) {
var str = '';
var provisioningStates = { 0: 'Not Activated (Pre)', 1: 'Not Activated (In)', 2: 'Activated' };
if (node.intelamt.ver == null || node.intelamt.state == null) { str += '<i>Unknown Version & State</i>'; } else {
str += provisioningStates[node.intelamt.state];
if (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>'; } }
str += (', v' + node.intelamt.ver);
}
if (node.intelamt.tls == 1) { str += ', <span title="Intel AMT is setup with TLS network security">TLS</span>'; }
if (node.intelamt.user == null || node.intelamt.user == '') {
if ((meshrights & 4) != 0) {
str += ', <i style=color:#FF0000;cursor:pointer title="Edit Intel&reg; AMT credentials" onclick=editDeviceAmtSettings("' + node._id + '")>No Credentials</i>';
} else {
str += ', <i style=color:#FF0000>No Credentials</i>';
}
}
str += ' ';
if ((meshrights & 4) != 0) {
str += '<img src=images/link4.png height=10 width=10 title="Edit Intel&reg; AMT credentials" style=cursor:pointer onclick=editDeviceAmtSettings("' + node._id + '")>';
}
x += addDeviceAttribute('Intel&reg; AMT', str);
}
// Attribute: Mesh Agent Tag
if ((node.agent != null) && (node.agent.tag != null) && (node.agent.tag != 'mailto:')) {
var tag = EscapeHtml(node.agent.tag);
if (tag.startsWith('mailto:')) { tag = '<a href="' + tag + '">' + tag.substring(7) + '</a>'; }
x += addDeviceAttribute('Agent Tag', tag);
}
// Attribute: Intel AMT
//if (node.intelamt && node.intelamt.user) { x += addDeviceAttribute('Intel&reg; AMT', node.intelamt.user); }
// Attribute: Connectivity (Only show this if more than just the agent is connected).
var connectivity = node.conn;
if (connectivity && connectivity > 1) {
var cstate = [];
if ((node.conn & 1) != 0) cstate.push('<span title="Mesh agent is connected and ready for use.">Mesh Agent</span>');
if ((node.conn & 2) != 0) cstate.push('<span title="Intel&reg; AMT CIRA is connected and ready for use.">Intel&reg; AMT CIRA</span>');
if ((node.conn & 4) != 0) cstate.push('<span title="Intel&reg; AMT is routable and ready for use.">Intel&reg; AMT</span>');
if ((node.conn & 8) != 0) cstate.push('<span title="Mesh agent is reachable using another agent as relay.">Mesh Relay</span>');
x += addDeviceAttribute('Connectivity', cstate.join(', '));
}
// Node grouping tags
var groupingTags = '<i>None</i>';
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>'; } }
x += addDeviceAttribute('Groups', '<span onclick=showEditNodeValueDialog(3) style=cursor:pointer>' + groupingTags + '</span>');
x += '</table><br />';
// Show action button, only show if we have permissions 4, 8, 64
if ((meshrights & 76) != 0) { x += '<input type=button value=Actions title="Perform power actions on the device" onclick=deviceActionFunction() />'; }
x += '<input type=button value=Notes title="View notes about this device" onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
//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() />'; }
QH('p10html', x);
// Show node last 7 days timeline
drawDeviceTimeline();
// Show bottom buttons
x = '<div style=float:right;font-size:x-small>';
if ((meshrights & 4) != 0) x += '<a style=cursor:pointer onclick=p10showDeleteNodeDialog("' + node._id + '") title="Remove this device">Delete Device</a>';
x += '</div><div style=font-size:x-small>';
if (mesh.mtype == 2) x += '<a style=cursor:pointer onclick=p10showNodeNetInfoDialog("' + node._id + '") title="Show device network interface information">Interfaces</a>&nbsp;';
if (xxmap != null) x += '<a style=cursor:pointer onclick=p10showNodeLocationDialog("' + node._id + '") title="Show device locations information">Location</a>&nbsp;';
if (((meshrights & 8) != 0) && (mesh.mtype == 2)) x += '<a style=cursor:pointer onclick=p10showMeshCmdDialog(1,"' + node._id + '") title="Traffic router used to connect to a device thru this server.">Router</a>&nbsp;';
// RDP link, show this link only of the remote machine is Windows.
if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0)) {
if ((node.agent.id > 0) && (node.agent.id < 5)) { x += '<a style=cursor:pointer onclick=p10clickOnce("' + node._id + '","RDP2",3389) title="Requires Microsoft ClickOnce support in your browser.">RDP</a>&nbsp;'; }
if (node.agent.id > 4) {
x += '<a style=cursor:pointer onclick=p10clickOnce("' + node._id + '","PSSH",22) title="Requires Microsoft ClickOnce support in your browser.">Putty</a>&nbsp;';
x += '<a style=cursor:pointer onclick=p10clickOnce("' + node._id + '","WSCP",22) title="Requires Microsoft ClickOnce support in your browser.">WinSCP</a>&nbsp;';
}
}
x += '</div><br>'
QH('p10html3', x);
// Set the node power state
powerstate = PowerStateStr(node.state);
//if (node.state == 0) { powerstate = 'Unknown State'; }
if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Agent connected">Agent connected</span>'; }
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>'; }
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>'; }
QH('MainComputerState', powerstate);
// Set the node icon
Q('MainComputerImage').setAttribute("src", "images/icons200-" + node.icon + "-1.png");
Q('MainComputerImage').className = ((!node.conn) || (node.conn == 0)?'gray':'');
// Setup/Refresh the desktop tab
setupTerminal();
setupFiles();
var consoleRights = ((meshrights & 16) != 0);
if (consoleRights) { setupConsole(); } else { if (panel == 15) { panel = 10; } }
// Show or hide the tabs
// mesh.mtype: 1 = Intel AMT only, 2 = Mesh Agent
// node.agent.caps (bitmask): 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console
QV('MainDevDesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0)) && (meshrights & 8));
QV('MainDevTerminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0)) && (meshrights & 8));
QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8));
QV('MainDevAmt', (node.intelamt != null) && (meshrights & 8));
QV('MainDevConsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0) && (userinfo.siteadmin == 0xFFFFFFFF));
QH('p15coreName', ((node.agent != null) && (node.agent.core != null))?node.agent.core:'');
// Setup/Refresh Intel AMT tab
var amtFrameNode = Q('p14iframe').contentWindow.getCurrentMeshNode();
if ((amtFrameNode != null) && (amtFrameNode._id != currentNode._id)) { Q('p14iframe').contentWindow.disconnect(); }
var online = ((node.conn & 6) != 0)?true:false; // If CIRA (2) or AMT (4) connected, enable Commander
Q('p14iframe').contentWindow.setConnectionState(online);
Q('p14iframe').contentWindow.setFrameHeight('650px');
Q('p14iframe').contentWindow.setAuthCallback(updateAmtCredentials);
// Display "action" button on desktop/terminal/files
QV('deskActionsBtn', (meshrights & 72) != 0); // 72 = Wake-up + Remote Control permissions
QV('termActionsBtn', (meshrights & 72) != 0);
QV('filesActionsBtn', (meshrights & 72) != 0);
// Request the power timeline
if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { powerTimelineReq = currentNode._id; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
// Reset the desktop tools
QV('DeskTools', false);
showDeskToolsProcesses();
// Ask for device events
refreshDeviceEvents();
}
setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
if (!panel) panel = 10;
go(panel);
}
function showNotes(readonly, noteid) {
if (xxdialogMode) return;
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>Notes can be viewed and changed by other administrators.<span>', noteid);
meshserver.send({ action: 'getNotes', id: decodeURIComponent(noteid) });
}
function showNotesEx(buttons, tag) { meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponent(Q('d2devNotes').value) }); }
function deviceToastFunction() {
if (xxdialogMode) return;
setDialogMode(2, "Device Toast", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
}
function deviceToastFunctionEx() {
meshserver.send({ action: 'toast', nodeids: [ currentNode._id ], title: 'MeshCentral', msg: Q('d2devToast').value });
}
function deviceActionFunction() {
if (xxdialogMode) return;
var meshrights = meshes[currentNode.meshid].links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
var x = "Select an operation to perform on this device.<br /><br />";
var y = '<select id=d2deviceop style=float:right;width:250px>';
if ((meshrights & 64) != 0) { y += '<option value=100>Wake-up</option>'; } // Wake-up permission
if ((meshrights & 8) != 0) { y += '<option value=4>Sleep</option><option value=3>Reset</option><option value=2>Power off</option>'; } // Remote control permission
y += '</select>';
x += addHtmlValue('Operation', y);
setDialogMode(2, "Device Action", 3, deviceActionFunctionEx, x);
}
function deviceActionFunctionEx() {
var op = Q('d2deviceop').value;
if (op == 100) {
// Device wake
meshserver.send({ action: 'wakedevices', nodeids: [ currentNode._id ] });
} else {
// Power operation
meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: op });
}
}
// Called when MeshCommander needs new credentials or updated credentials.
function updateAmtCredentials(forceDialog) {
var node = getNodeFromId(desktopNode._id);
if ((forceDialog == true) || (node.intelamt.user == null) || (node.intelamt.user == '')) {
editDeviceAmtSettings(desktopNode._id, updateAmtCredentialsEx);
} else {
Q('p14iframe').contentWindow.connectButtonfunctionEx();
}
}
function updateAmtCredentialsEx(button, tag) {
Q('p14iframe').contentWindow.connectButtonfunctionEx();
}
// Look to see if we need to update the device timeline
function updateDeviceTimeline() {
if ((meshserver.State != 2) || (powerTimelineNode == null) || (powerTimelineUpdate == null) || (currentNode == null)) return;
if ((powerTimelineNode == powerTimelineReq) && (currentNode._id == powerTimelineNode) && (powerTimelineUpdate < Date.now())) { powerTimelineUpdate = null; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
}
// Draw device power bars. The bars are 766px wide.
function drawDeviceTimeline() {
var timeline = null, now = Date.now();
if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
// Calculate when the timeline starts
var d = new Date();
d.setHours(0, 0, 0, 0);
d = new Date(d.getTime() - (1000 * 60 * 60 * 24 * 6));
var timelineStart = d.getTime();
// De-compact the timeline
var timeline2 = [];
if (timeline != null && timeline.length > 1) {
timeline2.push([ 0, timeline[1], timeline[0] ]); // Start, End, Power
var ct = timeline[1];
for (var i = 2; i < timeline.length; i += 2) {
var power = timeline[i], dt = now;
if (timeline.length > (i + 1)) { dt = timeline[i + 1]; }
timeline2.push([ ct, ct + dt, power ]); // Start, End, Power
ct = ct + dt;
}
}
// Draw the timeline
var x = '', count = 1, date = new Date();
date.setHours(0, 0, 0, 0);
for (var i = 0; i < 7; i++) {
var datavalue = '', start = date.getTime(), end = start + (1000 * 60 * 60 * 24);
for (var j in timeline2) {
var block = timeline2[j];
if (isTimeBlockInside(start, end, block[0], block[1]) == true) {
var ts = Math.max(start, block[0]);
var te = Math.min(Math.min(end, block[1]), now);
var width = Math.round((te - ts) / 112794);
if (width > 0) {
var title = powerStateStrings2[block[2]] + ' from ' + new Date(ts).toLocaleTimeString() + ' to ' + new Date(te).toLocaleTimeString() + '.';
datavalue += '<div title="' + title + '" style=display:table-cell;width:' + width + 'px;background-color:' + powerColor(block[2]) + ';height:16px></div>';
}
}
}
x += '<tr style=' + (((count % 2) == 0)?'background-color:#DDD':'') + '><td><div>&nbsp;' + date.toLocaleDateString() + '<div></div></div></td><td><div>' + datavalue + '</div></td></tr>';
++count;
date = new Date(date.getTime() - (1000 * 60 * 60 * 24)); // Substract one day
}
QH('p10html2', '<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:center;width:150px>Day</th><th scope=col style=text-align:center>7 Day Power State</th></tr>' + x + '</tbody></table>');
}
// Return a color for the given power state
function powerColor(x) { if (x < powerColorTable.length) { return powerColorTable[x]; } return 'yellow'; }
// Return true if the time block is visible within the start/end period
function isTimeBlockInside(start, end, blockStart, blockEnd) {
if ((blockStart < start) && (blockEnd > end)) return true; // Block is wider than timespan
if ((blockStart > start) && (blockStart < end)) return true;
if ((blockEnd > start) && (blockEnd < end)) return true;
return false;
}
function addDeviceAttribute(name, value) { return '<tr><td class=style7 style=width:180px>' + name + '</td><td class=style9 style=max-width:400px;overflow:hidden>' + value + '</td></tr>'; }
function editDeviceAmtSettings(nodeid, func) {
if (xxdialogMode) return;
var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
if ((meshrights & 4) == 0) return;
x += addHtmlValue('Username', '<input id=dp10username style=width:230px maxlength=32 autocomplete=nope placeholder="admin" onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
x += addHtmlValue('Password', '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
x += addHtmlValue('Security', '<select id=dp10tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
setDialogMode(2, "Edit Intel&reg; AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func });
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
Q('dp10tls').value = node.intelamt.tls;
validateDeviceAmtSettings();
}
function validateDeviceAmtSettings() {
QE('idx_dlgOkButton', passwordcheck(Q('dp10password').value));
}
function editDeviceAmtSettingsEx(button, tag) {
if (button == 2) {
// Delete button pressed, remove credentials
meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: '', pass: '' } });
} else {
// Change Intel AMT credentials
var amtuser = Q('dp10username').value;
if (amtuser == '') amtuser = 'admin';
var amtpass = Q('dp10password').value;
if (amtpass == '') amtuser = '';
meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
tag.node.intelamt.user = amtuser;
tag.node.intelamt.tls = Q('dp10tls').value;
if (tag.func) { setTimeout(tag.func, 300); }
}
}
function p10showDeleteNodeDialog(nodeid) {
if (xxdialogMode) return;
var x = "Are you sure you want to delete node \"" + EscapeHtml(currentNode.name) + "\"?<br /><br />";
x += "<input id=p10check type=checkbox onchange=p10validateDeleteNodeDialog() />Confirm";
setDialogMode(2, "Delete Node", 3, p10showDeleteNodeDialogEx, x, nodeid);
p10validateDeleteNodeDialog();
}
function p10validateDeleteNodeDialog() {
QE('idx_dlgOkButton', Q('p10check').checked);
}
function p10showDeleteNodeDialogEx(buttons, nodeid) {
meshserver.send({ action: 'removedevices', nodeids: [ nodeid ] });
}
function p10clickOnce(nodeid, protocol, port) {
meshserver.send({ action: 'getcookie', nodeid: nodeid, tcpport: port, tag: 'clickonce', protocol: protocol });
}
// Show current location
var d2map = null;
function p10showNodeLocationDialog() {
if ((xxdialogMode != null) && (xxdialogTag == '@xxmap')) { setDialogMode(0); } else { if (xxdialogMode) return; }
var markers = [], types = ['iploc', 'wifiloc', 'gpsloc', 'userloc'], boundingBox = null;
for (var loctype in types) {
if (currentNode[types[loctype]] != null) {
var loc = currentNode[types[loctype]].split(','), lat = parseFloat(loc[0]), lon = parseFloat(loc[1]);
if ((lat < 90) && (lat > -90) && (lon < 180) && (lon > -180)) { // Check valid lat/lon
var deviceMark = new ol.Feature({ geometry: new ol.geom.Point(ol.proj.fromLonLat([lon, lat])) });
deviceMark.setStyle(markerStyle(currentNode, parseInt(loctype) + 1));
markers.push(deviceMark);
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; } }
}
}
}
// Setup the device mark layer
var vectorSource = new ol.source.Vector({ features: markers });
var vectorLayer = new ol.layer.Vector({ source: vectorSource });
//var x = '<div><a href="https://www.google.com/maps/preview/@' + lat + ',' + lng + ',12z" target=_blank>Open in Google maps</a></div>';
var x = '<div id=d2map style=width:100%;height:300px></div>';
setDialogMode(2, "Device Location", 1, null, x, '@xxmap');
var clng = 0, clat = 0, zoom = 8;
if (boundingBox != null) {
var clat = (boundingBox[0] + boundingBox[2]) / 2;
var clng = (boundingBox[1] + boundingBox[3]) / 2;
var cscale = Math.max(Math.abs(boundingBox[0] - boundingBox[2]), Math.abs(boundingBox[1] - boundingBox[3]));
var i = 360, zoom = -2;
while (i > cscale) { zoom++; i = i / 2; }
}
if (markers.length == 1) { zoom = 8; }
// Setup the map
d2map = new ol.Map({
target: 'd2map',
interactions: ol.interaction.defaults({dragPan:false, mouseWheelZoom:false}),
layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer ],
view: new ol.View({ center: ol.proj.fromLonLat([clng, clat]), zoom: zoom })
});
}
// Show network interfaces
function p10showNodeNetInfoDialog() {
if (xxdialogMode) return;
setDialogMode(2, "Network Interfaces", 1, null, "<div id=d2netinfo>Loading...</div>", 'if' + currentNode._id );
meshserver.send({ action: 'getnetworkinfo', nodeid: currentNode._id });
}
// Show router dialog
function p10showMeshCmdDialog(mode, nodeid) {
if (xxdialogMode) return;
var y = "<select id=aginsSelect onclick=meshCmdOsClick() style=width:236px>";
y += "<option value=3>Windows (32bit)</option>";
y += "<option value=4>Windows (64bit)</option>";
y += "<option value=5>Linux x86 (32bit)</option>";
y += "<option value=6>Linux x86 (64bit)</option>";
y += "<option value=25>Linux ARM, Raspberry Pi (32bit)</option>";
y += "</select>";
var x = "";
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 />'; }
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 />'; }
x += addHtmlValue('Operating System', y);
x += addHtmlValue('MeshCmd', '<a id=meshcmddownloadid href="meshagents?meshcmd=3" target="_blank"></a>');
if (mode == 0) { x += addHtmlValue('Action File', '<a href="meshagents?meshaction=generic" target="_blank">MeshAction (.txt)</a>'); }
if (mode == 1) { x += addHtmlValue('Action File', '<a href="meshagents?meshaction=route&nodeid=' + nodeid + '" target="_blank">MeshAction (.txt)</a>'); }
x += "</div>";
setDialogMode(2, ["Download MeshCmd","Network Router"][mode], 9, null, x);
meshCmdOsClick();
}
function meshCmdOsClick() {
var os = Q('aginsSelect').value, osn = '';
Q('meshcmddownloadid').href = "meshagents?meshcmd=" + os;
if (os == 3) { osn = 'MeshCmd (Win32 executable)'; }
if (os == 4) { osn = 'MeshCmd (Win64 executable)'; }
if (os == 5) { osn = 'MeshCmd (Linux x86, 32bit)'; }
if (os == 6) { osn = 'MeshCmd (Linux x86, 64bit)'; }
if (os == 25) { osn = 'MeshCmd (Linux ARM, 32bit)'; }
QH('meshcmddownloadid', osn);
}
function p10showiconselector() {
if (xxdialogMode) return;
var mesh = meshes[currentNode.meshid];
var meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
if ((meshrights & 4) == 0) return;
var x = '<br><div style=display:inline-block;width:40px></div>';
x += '<div style=display:inline-block class=i1 onclick=p10setIcon(1)></div>';
x += '<div style=display:inline-block class=i2 onclick=p10setIcon(2)></div>';
x += '<div style=display:inline-block class=i3 onclick=p10setIcon(3)></div>';
x += '<div style=display:inline-block class=i4 onclick=p10setIcon(4)></div>';
x += '<div style=display:inline-block class=i5 onclick=p10setIcon(5)></div>';
x += '<div style=display:inline-block class=i6 onclick=p10setIcon(6)></div><br><br>';
setDialogMode(2, "Icon Selection", 0, null, x);
QV('id_dialogclose', true);
}
function p10setIcon(icon) {
setDialogMode(0);
meshserver.send({ action: 'changedevice', nodeid: currentNode._id, icon: icon });
}
var showEditNodeValueDialog_modes = ['Device Name', 'Hostname', 'Description', 'Groups'];
var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc', 'tags'];
var showEditNodeValueDialog_modes3 = ['', '', '', 'Group1, Group2, Group3'];
function showEditNodeValueDialog(mode) {
if (xxdialogMode) return;
var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:230px maxlength=64 placeholder="' + showEditNodeValueDialog_modes3[mode] + '" onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode);
var v = currentNode[showEditNodeValueDialog_modes2[mode]];
if (v == null) v = '';
if (Array.isArray(v)) { v = v.join(', '); }
Q('dp10devicevalue').value = v;
p10editdevicevalueValidate();
Q('dp10devicevalue').focus();
}
function showEditNodeValueDialogEx(button, mode) {
var x = { action: 'changedevice', nodeid: currentNode._id };
x[showEditNodeValueDialog_modes2[mode]] = Q('dp10devicevalue').value;
meshserver.send(x);
}
function p10editdevicevalueValidate(mode, e) {
var x = ((mode > 1) || (Q('dp10devicevalue').value.length > 0));
QE('idx_dlgOkButton', x);
if ((e != null) && (x == true) && (e.keyCode == 13)) { dialogclose(1); }
}
//
// DESKTOP
//
var desktopNode;
function setupDesktop() {
// Setup the remote desktop
if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); delete desktop; desktopNode = null; desktop = null; }
// If the device desktop is already connected in multi-desktop, use that.
if ((desktopNode != currentNode) || (desktop == null)) {
var xdesk = multiDesktop[currentNode._id];
if (xdesk != null) {
// This device already has a canvas, use it.
QH('DeskParent', '');
var c = xdesk.m.CanvasId;
c.setAttribute('id', 'Desk');
c.setAttribute('style', 'width:100%;-ms-touch-action:none;margin-left:0px');
c.setAttribute('onmousedown', 'dmousedown(event)');
c.setAttribute('onmouseup', 'dmouseup(event)');
c.setAttribute('onmousemove', 'dmousemove(event)');
c.removeAttribute('onclick');
Q('DeskParent').appendChild(c);
desktop = xdesk;
if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
desktop.onStateChanged = onDesktopStateChange;
desktopNode = currentNode;
onDesktopStateChange(desktop, desktop.State);
delete multiDesktop[currentNode._id];
} else {
// Device is not already connected, just setup a blank canvas
QH('DeskParent', '<canvas id=Desk width=640 height=200 style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
desktopNode = currentNode;
}
// Setup the mouse wheel
Q('Desk').addEventListener('DOMMouseScroll', function (e) { return dmousewheel(e); });
Q('Desk').addEventListener('mousewheel', function (e) { return dmousewheel(e); });
}
desktopNode = currentNode;
updateDesktopButtons();
// On some browsers like IE, we can't save screen shots. Hide the scheenshot/capture buttons.
if (!Q('Desk')['toBlob']) { QV('deskSaveBtn', false); }
}
// Show and enable the right buttons
function updateDesktopButtons() {
var mesh = meshes[currentNode.meshid];
var deskState = 0;
if (desktop != null) { deskState = desktop.State; }
// Show the right buttons
QV('disconnectbutton1span', (deskState != 0));
QV('connectbutton1span', (deskState == 0) && (mesh.mtype == 2));
QV('connectbutton1hspan', (deskState == 0) && (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
// Show the right settings
QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == 0) || (desktop.contype == 2)));
QV('d7meshkvm', (mesh.mtype == 2) && ((deskState == false) || (desktop.contype == 1)));
// Enable buttons
var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable remote desktop
QE('connectbutton1', online);
var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
QE('connectbutton1h', hwonline);
QE('deskSaveBtn', deskState == 3);
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus));
QE('DeskCAD', deskState == 3);
QE('DeskWD', deskState == 3);
QE('deskkeys', deskState == 3);
QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5));
QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5));
QE('DeskToolsButton', online);
QV('DeskToastButton', (currentNode.agent) && (currentNode.agent.id < 5));
QE('DeskToastButton', online);
if (online == false) QV('DeskTools', false);
}
// Debug
var autoConnectDesktopTimer = null;
function autoConnectDesktop(e) { if (autoConnectDesktopTimer == null) { autoConnectDesktopTimer = setInterval(connectDesktop, 100); } else { clearInterval(autoConnectDesktopTimer); autoConnectDesktopTimer = null; } }
function connectDesktop(e, contype) {
if (desktop == null) {
desktopNode = currentNode;
if (contype == 2) {
// Setup the Intel AMT remote desktop
if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'));
desktop.debugmode = debugmode;
desktop.onStateChanged = onDesktopStateChange;
desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
desktop.m.useZRLE = (desktopsettings.encoding < 3);
desktop.m.showmouse = desktopsettings.showmouse;
desktop.m.onScreenSizeChange = deskAdjust;
desktop.Start(desktopNode._id, 16994, '*', '*', 0);
desktop.contype = 2;
} else {
// Setup the Mesh Agent remote desktop
desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort);
desktop.debugmode = debugmode;
desktop.m.debugmode = debugmode;
desktop.attemptWebRTC = attemptWebRTC;
desktop.onStateChanged = onDesktopStateChange;
desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
desktop.m.ScalingLevel = desktopsettings.scaling;
desktop.m.FrameRateTimer = desktopsettings.framerate;
desktop.m.onDisplayinfo = deskDisplayInfo;
desktop.m.onScreenSizeChange = deskAdjust;
desktop.Start(desktopNode._id);
desktop.contype = 1;
}
} else {
// Disconnect and clean up the remote desktop
desktop.Stop();
delete desktop;
desktopNode = desktop = null;
}
}
function onDesktopStateChange(xdesktop, state) {
var xstate = state;
if ((xstate == 3) && (xdesktop.contype == 2)) { xstate++; }
var str = StatusStrs[xstate];
if ((desktop != null) && (desktop.webRtcActive == true)) { str += ', WebRTC'; }
//if (desktop.m.stopInput == true) { str += ', Loopback'; }
QH('deskstatus', str);
switch (state) {
case 0:
// Disconnect and clean up the remote desktop
desktop.Stop();
delete desktop;
desktopNode = desktop = null;
QV('DeskFocus', false);
QV('termdisplays', false);
deskFocusBtn.value = 'All Focus';
if (fullscreen == true) { deskToggleFull(); }
break;
case 2:
break;
}
updateDesktopButtons();
deskAdjust();
setTimeout(deskAdjust, 50);
}
function showDesktopSettings() {
applyDesktopSettings();
updateDesktopButtons();
setDialogMode(7, "Remote Desktop Settings", 3, showDesktopSettingsChanged);
}
function showDesktopSettingsChanged() {
desktopsettings.encoding = d7desktopmode.value;
desktopsettings.showfocus = d7showfocus.checked;
desktopsettings.showmouse = d7showcursor.checked;
desktopsettings.quality = d7bitmapquality.value;
desktopsettings.scaling = d7bitmapscaling.value;
desktopsettings.framerate = d7framelimiter.value;
localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
applyDesktopSettings();
if (desktop) {
if (desktop.contype == 1) {
if (desktop.State != 0) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
}
if (desktop.contype == 2) {
if (desktopsettings.showfocus == false) { desktop.m.focusmode = 0; deskFocusBtn.value = 'All Focus'; }
if (desktop.State != 0) { desktop.Stop(); setTimeout(function () { connectDesktop(null, 2); }, 50); }
}
}
}
function applyDesktopSettings() {
var r = '', ops = (features & 512)?[90,70,50,40,30,20,10,5,1]:[50,40,30,20,10,5,1];
for (var i in ops) { r += '<option value=' + ops[i] + '>' + ops[i] + '%</option>'; }
QH('d7bitmapquality', r);
d7desktopmode.value = desktopsettings.encoding;
d7showfocus.checked = desktopsettings.showfocus;
d7showcursor.checked = desktopsettings.showmouse;
d7bitmapquality.value = 40; // Default value
if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
d7bitmapscaling.value = desktopsettings.scaling;
if (desktopsettings.framerate) { d7framelimiter.value = desktopsettings.framerate; }
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus));
}
var fullscreen = false;
function deskToggleFull() {
fullscreen = !fullscreen;
QV('mastheadx', !fullscreen);
QV('masthead', !fullscreen);
QV('topbar', !fullscreen);
QV('p11deviceNameHeader', !fullscreen);
QV('footer', !fullscreen);
QV('column_l_bottomgap', !fullscreen);
QV('idx_deskFullBtn2', fullscreen);
QV('deskFullBtn', !fullscreen);
if (fullscreen) {
QS('container').width = '100%';
QS('container')['border-right'] = '0';
QS('container')['border-left'] = '0';
QS('column_l').padding = '0';
QS('column_l').width = '100%';
} else {
QS('container').width = '960px';
QS('container')['border-right'] = '1px solid #b7b7b7';
QS('container')['border-left'] = '1px solid #b7b7b7';
QS('column_l').padding = '0 15px';
QS('column_l').width = '930px';
toggleFullScreen();
}
deskAdjust();
}
function deskToggleFocus() {
desktop.m.focusmode = (desktop.m.focusmode + 64) % 192;
Q('deskFocusBtn').value = ['All Focus', 'Small Focus', 'Large Focus'][desktop.m.focusmode / 64];
}
function deskAdjust() {
var x = (Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - (Q('deskarea1').clientHeight + Q('deskarea2').clientHeight + Q('Desk').clientHeight + Q('deskarea4').clientHeight + 2)) / 2;
if (fullscreen) {
document.documentElement.style.overflow = 'hidden';
QS('deskarea3x').height = null;
if (x < 0) {
var mh = (Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - (Q('deskarea1').clientHeight + Q('deskarea2').clientHeight + Q('deskarea4').clientHeight));
var mw = 9999;
if (desktop) { mw = (desktop.m.width / desktop.m.height) * mh; }
QS('Desk')['max-height'] = mh + 'px';
QS('Desk')['max-width'] = mw + 'px';
x = 0;
} else {
QS('Desk')['max-height'] = null;
QS('Desk')['max-width'] = null;
}
QS('Desk')['margin-top'] = x + 'px';
QS('Desk')['margin-bottom'] = x + 'px';
} else {
document.documentElement.style.overflow = 'auto';
QS('deskarea3x').height = (desktop)?'40px':'400px';
QS('Desk')['max-height'] = null;
QS('Desk')['max-width'] = null;
QS('Desk')['margin-top'] = '0';
QS('Desk')['margin-bottom'] = '0';
}
}
// Remote desktop special key combos for Windows
function deskSendKeys() {
if (xxdialogMode || desktop == null || desktop.State != 3) return;
var ks = Q('deskkeys').value;
if (ks == 0) { // WIN+Down arrow
if (desktop.contype == 2) {
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
} else {
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
}
} else if (ks == 1) { // WIN+Up arrow
if (desktop.contype == 2) {
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
} else {
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
}
} else if (ks == 2) { // WIN+L arrow
if (desktop.contype == 2) {
desktop.m.sendkey([[0xffe7,1],[0x6c,1],[0x6c,0],[0xffe7,0]]); // Intel AMT: Meta-left down, 'l' press, 'l' release, Meta-left release
} else {
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
}
} else if (ks == 3) { // WIN+M arrow
if (desktop.contype == 2) {
desktop.m.sendkey([[0xffe7,1],[0x6d,1],[0x6d,0],[0xffe7,0]]); // Intel AMT: Meta-left down, 'm' press, 'm' release, Meta-left release
} else {
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
}
} else if (ks == 4) { // Shift+WIN+M arrow
if (desktop.contype == 2) {
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
} else {
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
}
}
}
// Send CTRL-ALT-DEL
function sendCAD() {
if (xxdialogMode || desktop == null || desktop.State != 3) return;
desktop.m.sendcad();
}
// Show process dialogs
function toggleDeskTools() {
if (xxdialogMode) return;
if (QS('DeskTools').display == 'none') {
QV('DeskTools', true);
Q('DeskTools').nodeid = currentNode._id;
refreshDeskTools();
} else {
QV('DeskTools', false);
}
}
// Refresh all of the desktop tool panels
function refreshDeskTools() {
QV('DeskToolsRefreshButton', false);
setTimeout(refreshDeskToolsEx, 500);
meshserver.send({ action: 'msg', type:'ps', nodeid: currentNode._id });
}
function refreshDeskToolsEx() { QV('DeskToolsRefreshButton', true); }
var deskTools = { sort: 1, msg: null };
function sortProcess(sort) { deskTools.sort = sort; showDeskToolsProcesses(deskTools.msg); }
function sortProcessPid(a, b) { if (a.p > b.p) return 1; if (a.p < b.p) return (-1); return 0; }
function sortProcessName(a, b) { if (a.d > b.d) return 1; if (a.d < b.d) return (-1); return 0; }
function showDeskToolsProcesses(message) {
deskTools.msg = message;
if (message == null) { QH('DeskToolsProcesses', ''); return; }
if (Q('DeskTools').nodeid != message.nodeid) return;
var p = [], processes = null;
try { processes = JSON.parse(message.value); } catch (e) { }
console.log(processes);
if (processes != null) {
for (var pid in processes) { p.push( { p:parseInt(pid), c:processes[pid].cmd, d:processes[pid].cmd.toLowerCase(), u: processes[pid].user } ); }
if (deskTools.sort == 0) { p.sort(sortProcessPid); } else if (deskTools.sort == 1) { p.sort(sortProcessName); }
var x = '';
for (var i in p) { if (p[i].p != 0) { x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + p[i].p + '</div><a style=float:right;padding-right:5px;cursor:pointer title="Stop process" onclick=stopProcess(' + p[i].p + ',"' + p[i].c + '")><img width=10 height=10 src="images/trash.png"></a><div style=float:right;padding-right:5px>' + (p[i].u?p[i].u:'') + '</div><div>' + p[i].c + '</div></div>'; } }
QH('DeskToolsProcesses', x);
}
}
// Toggle mouse and keyboard input
function toggleKvmControl() { putstore('DeskControl', (Q("DeskControl").checked?1:0)); }
// Save the desktop image to file
function deskSaveImage() {
if (xxdialogMode || desktop == null || desktop.State != 3) return;
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);
Q("Desk")['toBlob'](function (blob) { saveAs(blob, n + ".jpg"); });
}
function deskDisplayInfo(sender, info, selDisplay, selItem) {
var txt = Q('termdisplays').value;
if (info.length > 0) { var options = ''; for (var x in info) { options += '<option' + ((txt == info[x])?' selected':'') + '>' + info[x] + '</option>'; } QH('termdisplays', options); }
QV('termdisplays', info.length > 0);
}
function deskGetDisplayNumbers(e) { desktop.m.GetDisplayNumbers(); }
function deskSetDisplay(e) {
var display = 0, txt = Q('termdisplays').value;
if (txt == "All Displays") display = 65535; else display = parseInt(txt.substring(8));
desktop.m.SetDisplay(display);
}
function dmousedown(e) { if (!xxdialogMode && desktop != null && Q('DeskControl').checked) desktop.m.mousedown(e) }
function dmouseup(e) { if (!xxdialogMode && desktop != null && Q('DeskControl').checked) desktop.m.mouseup(e) }
function dmousemove(e) { if (!xxdialogMode && desktop != null && Q('DeskControl').checked) desktop.m.mousemove(e) }
function dmousewheel(e) { if (!xxdialogMode && desktop != null && Q('DeskControl').checked && desktop.m.mousewheel) { desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
function drotate(x) { if (!xxdialogMode && desktop != null) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); deskAdjust(); } }
function stopProcess(id, name) { setDialogMode(2, "Process Control", 3, stopProcessEx, 'Stop process #' + id + ' "' + name + '"?', id); }
function stopProcessEx(buttons, tag) { meshserver.send({ action: 'msg', type:'pskill', nodeid: currentNode._id, value: tag }); setTimeout(refreshDeskTools, 300); }
//
// TERMINAL
//
var terminalNode;
function setupTerminal() {
// Setup the terminal
if ((terminalNode != currentNode) && (terminal != null)) { terminal.Stop(); delete terminal; terminal = null; }
terminalNode = currentNode;
updateTerminalButtons();
}
// Show and enable the right buttons
function updateTerminalButtons() {
var mesh = meshes[terminalNode.meshid];
var termState = ((terminal != null) && (terminal.state != 0));
// Show the right buttons
QV('disconnectbutton2span', (termState == true));
QV('connectbutton2span', (termState == false) && (mesh.mtype == 2));
QV('connectbutton2hspan', (termState == false) && (terminalNode.intelamt != null && ((terminalNode.intelamt.ver != null) || (mesh.mtype == 1))));
// Enable buttons
var online = ((terminalNode.conn & 1) != 0); // If Agent (1) connected, enable Terminal
QE('connectbutton2', online);
var hwonline = ((terminalNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
QE('connectbutton2h', hwonline);
QE('ctrlcbutton', termState);
QE('ctrlxbutton', termState);
QE('escbutton', termState);
QE('bsbutton', termState);
QE('pastebutton', termState);
QE('specialkeylist', termState);
QE('specialkeylistinput', termState);
}
// Called when the terminal state changes
function onTerminalStateChange(xterminal, state) {
var xstate = state;
if ((xstate == 3) && (xterminal.contype == 2)) { xstate++; }
var str = StatusStrs[xstate];
if (terminal.webRtcActive == true) { str += ', WebRTC'; }
QH('termstatus', str);
switch (state) {
case 0:
// Disconnected, clear the terminal
xterminal.m.TermResetScreen();
xterminal.m.TermDraw();
if (terminal != null) {
terminal.Stop();
delete terminal;
terminal = null;
}
break;
case 3:
break;
}
updateTerminalButtons();
}
// DEBUG
var autoConnectTerminalTimer = null;
function autoConnectTerminal(e) { if (autoConnectTerminalTimer == null) { autoConnectTerminalTimer = setInterval(connectTerminal, 100); } else { clearInterval(autoConnectTerminalTimer); autoConnectTerminalTimer = null; } }
function connectTerminal(e, contype) {
if (!terminal) {
if (contype == 2) {
// Setup the Intel AMT terminal
if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal); return; }
terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term'));
terminal.debugmode = debugmode;
terminal.onStateChanged = onTerminalStateChange;
terminal.Start(terminalNode._id, 16994, '*', '*', 0);
terminal.contype = 2;
} else {
// Setup a mesh agent terminal
terminal = CreateAgentRedirect(meshserver, CreateAmtRemoteTerminal('Term'), serverPublicNamePort);
terminal.debugmode = debugmode;
terminal.m.debugmode = debugmode;
terminal.m.lineFeed = ([1,2,3,4,21,22].indexOf(currentNode.agent.id) >= 0)?'\r\n':'\r'; // On windows, send \r\n, on Linux only \r
terminal.attemptWebRTC = attemptWebRTC;
terminal.onStateChanged = onTerminalStateChange;
terminal.Start(terminalNode._id);
terminal.contype = 1;
}
} else {
//QH('Term', '');
terminal.Stop();
delete terminal;
terminal = null;
}
Q('connectbutton2').blur(); // Deselect the connect button so the button does not get key presses.
}
var terminalEmulations = ['UTF8 Terminal', 'Extended ASCII', 'Intel ASCII'];
function termToggleType() {
if (!terminal || xxdialogMode) return;
terminal.m.terminalEmulation = (terminal.m.terminalEmulation + 1) % 3;
Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
Q('id_ttypebutton').blur(); // Deselect the connect button so the button does not get key presses.
}
var fxEmulations = ['Intel (F10 = ESC+[OM)', 'Alternate (F10 = ESC+0)', 'VT100+ (F10 = ESC+[OY)'];
function termToggleFx() {
if (!terminal || xxdialogMode) return;
terminal.m.fxEmulation = (terminal.m.fxEmulation + 1) % 3;
Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
Q('id_tfxkeysbutton').blur(); // Deselect the connect button so the button does not get key presses.
}
function termSendKey(key, id) {
if (!terminal || xxdialogMode) return;
terminal.m.TermSendKey(key);
Q(id).blur(); // Deselect the connect button so the button does not get key presses.
}
function showTermPasteDialog() {
if (!terminal || xxdialogMode) return;
Q('pastebutton').blur();
setDialogMode(2, "Paste", 3, showTermPasteDialogEx, '<textarea id=d2pasteText style="width:100%;height:184px;resize:none"></textarea>');
Q('d2pasteText').focus();
}
function showTermPasteDialogEx() {
if (!terminal) return;
terminal.m.TermSendKeys(Q('d2pasteText').value);
}
// Send special key
function sendSpecialKey() {
terminal.m.TermSendKey(Q('specialkeylist').value);
Q('specialkeylist').blur();
Q('specialkeylistinput').blur();
}
//
// FILES
//
var filesNode;
function setupFiles() {
// Setup the files tab
var samenode = (filesNode == currentNode);
filesNode = currentNode;
var online = ((filesNode.conn & 1) != 0)?true:false; // If Agent (1) connected, enable Terminal
QE('p13Connect', online);
if (((samenode == false) || (online == false)) && files) { files.Stop(); delete files; files = null; }
}
function onFilesStateChange(xfiles, state) {
p13Connect.value = (state == 0) ? 'Connect' : 'Disconnect';
var str = StatusStrs[state];
if (files.webRtcActive == true) { str += ', WebRTC'; }
Q('p13Status').textContent = str;
switch (state) {
case 0:
// Disconnected, clear the files
QH('p13files', '');
p13filetree = null;
p13filetreelocation = [];
QH('p13currentpath', '');
QE('p13FolderUp', false);
p13setActions();
if (files != null) { files.Stop(); delete files; files = null; }
break;
case 3:
p13targetpath = '';
files.send(JSON.stringify({ action: 'ls', reqid: 1, path: '' }));
break;
}
}
function CreateRemoteFiles(onFileUpdate) {
var obj = { protocol: 5 };
obj.onFileUpdate = onFileUpdate;
obj.xxStateChange = function(state) { }
obj.ProcessData = function(data) { obj.onFileUpdate(data); }
return obj;
}
// Debug Only
var autoConnectFilesTimer = null;
function autoConnectFiles(e) { if (autoConnectFilesTimer == null) { autoConnectFilesTimer = setInterval(connectFiles, 100); } else { clearInterval(autoConnectFilesTimer); autoConnectFilesTimer = null; } }
function connectFiles(e) {
if (!files) {
// Setup a mesh agent files
files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort);
files.attemptWebRTC = attemptWebRTC;
files.onStateChanged = onFilesStateChange;
files.Start(filesNode._id);
} else {
//QH('Term', '');
files.Stop();
delete files;
files = null;
}
p13clipboard = p13clipboardFolder = null;
p13clipboardCut = 0;
p13updateClipview();
p13oldlinkpath = null;
}
var p13filetree = null;
var p13targetpath = null;
var p13filetreelocation = [];
function p13gotFiles(data) {
//console.log('p13gotFiles', data);
if ((data.length > 0) && (data.charCodeAt(0) != 123)) { p13gotDownloadBinaryData(data); return; }
//console.log('p13gotFiles', data);
data = JSON.parse(data);
if (data.action == 'download') { p13gotDownloadCommand(data); return; }
data.path = data.path.replace(/\//g, "\\");
if ((p13filetree != null) && (data.path == p13filetree.path)) {
// This is an update to the same folder
var checkedNames = p13getCheckedNames();
p13filetree = data;
p13updateFiles(checkedNames);
} else {
// Make both paths use the same seperator not start with /
var x1 = data.path.replace(/\//g, "\\");
var x2 = p13targetpath.replace(/\//g, "\\");
while ((x1.length > 0) && (x1[0] == '\\')) { x1 = x1.substring(1); }
while ((x2.length > 0) && (x2[0] == '\\')) { x2 = x2.substring(1); }
if ((x1 == x2) || ((data.path == '\\') && (p13targetpath == ''))) {
// This is a different folder
p13filetree = data;
p13updateFiles();
}
}
}
function p13getCheckedNames() {
// Save all existing checked boxes
var checkedNames = [], checkboxes = document.getElementsByName('fd');
for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedNames.push(p13filetree.dir[checkboxes[i].value].n) }; }
return checkedNames;
}
//var p13oldlinkpath = null;
function p13updateFiles(checkedNames) {
var html1 = '', html2 = '', displayPath = '<a style=cursor:pointer onclick=p13folderup(0)>Root</a>', fullPath = 'Root';
// Work on parsing the file path
var x = p13filetree.path.split('\\');
p13filetreelocation = [];
for (var i in x) { if (x[i] != '') { p13filetreelocation.push(x[i]); } } // Remove empty spaces
for (var i in p13filetreelocation) { displayPath += ' / <a style=cursor:pointer onclick=p13folderup(' + (parseInt(i) + 1) + ')>' + p13filetreelocation[i] + '</a>' } // Setup the path we display
var newlinkpath = p13filetreelocation.join('/');
// Sort the files
var filetreexx = p13sort_files(p13filetree.dir);
// Display all files and folders at this location
for (var i in filetreexx) {
// Figure out the name and shortname
var f = filetreexx[i], name = f.n, shortname;
shortname = name;
if (name.length > 70) { shortname = '<span title="' + EscapeHtml(name) + '">' + EscapeHtml(name.substring(0, 70)) + "...</span>"; } else { shortname = EscapeHtml(name); }
name = EscapeHtml(name);
// Figure out the date
var fdatestr = '';
if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + "/" + (fdate.getDate()) + "/" + fdate.getFullYear() + " " + fdate.toLocaleTimeString() + "&nbsp;"; }
// Figure out the size
var fsize = '';
if (f.s != null) { fsize = getFileSizeStr(f.s); }
var h = '';
if (f.t < 3) {
var right = '', title = '';
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 title=\"" + title + "\">" + right + "</span><span><div class=fileIcon" + f.t + "></div><a style=cursor:pointer onclick=p13folderset(\"" + encodeURIComponent(f.nx) + "\")>" + shortname + "</a></span></div>";
} else {
var link = shortname;
if (f.s > 0) { link = "<a target=\"_blank\" style=cursor:pointer onclick=\"p13downloadfile('" + encodeURIComponent(newlinkpath + '/' + name) + "','" + encodeURIComponent(name) + "'," + f.s + ")\">" + shortname + "</a>"; }
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 class=fsize>" + fdatestr + "</span><span style=float:right>" + fsize + "</span><span><div class=fileIcon" + f.t + "></div>" + link + "</span></div>";
}
if (f.t < 3) { html1 += h; } else { html2 += h; }
}
// Display the files and path
QH('p13files', html1 + html2);
QH('p13currentpath', displayPath);
QE('p13FolderUp', p13filetreelocation.length != 0);
// Re-check all boxes if needed using names
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; } } }
// Update the actions buttons
p13setActions();
}
function p13folderset(x) {
p13targetpath = joinPaths(p13filetree.path, p13filetree.dir[x].n).split('\\').join('/');
files.send(JSON.stringify({ action: 'ls', reqid: 1, path: p13targetpath }));
}
function p13folderup(x) {
if (x == null) { p13filetreelocation.pop(); } else { while (p13filetreelocation.length > x) { p13filetreelocation.pop(); } }
p13targetpath = p13filetreelocation.join('/');
files.send(JSON.stringify({ action: 'ls', reqid: 1, path: p13targetpath }));
}
var p13sortorder;
function p13sort_filename(a, b) { if (a.ln > b.ln) return (1 * p13sortorder); if (a.ln < b.ln) return (-1 * p13sortorder); return 0; }
function p13sort_timestamp(a, b) { if (a.d > b.d) return (1 * p13sortorder); if (a.d < b.d) return (-1 * p13sortorder); return 0; }
function p13sort_bysize(a, b) { if (a.s == b.s) return p13sort_filename(a, b); return (((a.s - b.s)) * p13sortorder); }
function p13sort_files(files) {
var r = [], sortselection = Q('p13sortdropdown').value;
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]); }
p13sortorder = 1;
if (sortselection > 3) { p13sortorder = -1; sortselection -= 3; }
if (sortselection == 1) { r.sort(p13sort_filename); }
else if (sortselection == 2) { r.sort(p13sort_bysize); }
else if (sortselection == 3) { r.sort(p13sort_timestamp); }
return r;
}
function p13setActions() {
if (p13filetree == null) {
QE('p13DeleteFileButton', false);
QE('p13NewFolderButton', false);
QE('p13UploadButton', false);
QE('p13RenameFileButton', false);
QE('p13SelectAllButton', false);
Q('p13SelectAllButton').value = 'Select All';
QE('p13RefreshButton', false);
QE('p13CutButton', false);
QE('p13CopyButton', false);
QE('p13PasteButton', false);
} else {
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)
var winAgent = ((currentNode.agent.id > 0) && (currentNode.agent.id < 5));
QE('p13DeleteFileButton', (cc > 0) && ((p13filetreelocation.length > 0) || (winAgent == false)));
QE('p13NewFolderButton', ((p13filetreelocation.length > 0) || (winAgent == false)));
QE('p13UploadButton', ((p13filetreelocation.length > 0) || (winAgent == false)));
QE('p13RenameFileButton', (cc == 1) && ((p13filetreelocation.length > 0) || (winAgent == false)));
QE('p13SelectAllButton', tc > 0);
Q('p13SelectAllButton').value = (cc > 0 ? 'Select None' : 'Select All');
QE('p13RefreshButton', true);
QE('p13CutButton', (cc > 0) && (cc == sfc) && ((p13filetreelocation.length > 0) || (winAgent == false)));
QE('p13CopyButton', (cc > 0) && (cc == sfc) && ((p13filetreelocation.length > 0) || (winAgent == false)));
QE('p13PasteButton', ((p13filetreelocation.length > 0) || (winAgent == false)) && ((p13clipboard != null) && (p13clipboard.length > 0)));
}
}
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; }
function p13getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fd'); return checkboxes.length; }
function p13selectallfile() { var nv = (p13getFileSelCount() == 0), checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p13setActions(); }
function p13createfolder() { setDialogMode(2, "New Folder", 3, p13createfolderEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% />'); focusTextBox('p13renameinput'); p13fileNameCheck(); }
function p13createfolderEx() { files.send(JSON.stringify({ action: 'mkdir', reqid: 1, path: p13filetreelocation.join('/') + '/' + Q('p13renameinput').value })); p13folderup(999); }
function p13deletefile() { var cc = getFileSelCount(); setDialogMode(2, "Delete", 3, p13deletefileEx, (cc > 1)?('Delete ' + cc + ' selected items?'):('Delete selected item?')); }
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.send(JSON.stringify({ action: 'rm', reqid: 1, path: p13filetreelocation.join('/'), delfiles: delfiles })); p13folderup(999); }
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(); }
function p13renamefileEx(b, t) { t.newname = Q('p13renameinput').value; files.send(JSON.stringify(t)); p13folderup(999); }
function p13fileNameCheck(e) { var x = isFilenameValid(Q('p13renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); } }
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'); }
function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); }
var p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0;
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(); }
function p13pasteFile() { var x = ''; if ((p13clipboard != null) && (p13clipboard.length > 0)) { x = 'Confim ' + (p13clipboardCut == 0?'copy':'move') + ' of ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1)?'s':'') + ' to this location?' } setDialogMode(2, "Paste", 3, p13pasteFileEx, x); }
function p13pasteFileEx() { files.send(JSON.stringify({ 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(); } }
function p13updateClipview() { var x = ''; if ((p13clipboard != null) && (p13clipboard.length > 0)) { x = 'Holding ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1)?'s':'') + ' for ' + (p13clipboardCut == 0?'copy':'move') + ', <a onclick=p13clearClip() style=cursor:pointer>Clear</a>.' } QH('p13bottomstatus', x); p13setActions(); }
function p13clearClip() { p13clipboard = null; p13clipboardFolder = null; p13clipboardCut = 0; p13updateClipview(); }
function p13fileDragDrop(e) {
haltEvent(e);
QV('p13bigfail', false);
QV('p13bigok', false);
if (e.dataTransfer == null || e.dataTransfer.files.length == 0 || p13filetree == null) return;
p13doUploadFiles(e.dataTransfer.files);
}
var p13dragtimer = null;
function p13fileDragOver(e) {
haltEvent(e);
if (p13dragtimer != null) { clearTimeout(p13dragtimer); p13dragtimer = null; }
var ac = (p13filetree != null); // Set to true if we can accept the file
QV('p13bigok', ac);
QV('p13bigfail', !ac);
}
function p13fileDragLeave(e) {
haltEvent(e);
if (e.target.id != "p13filetable") {
QV('p13bigfail', false);
QV('p13bigok', false);
} else {
p13dragtimer = setTimeout("QV('p13bigfail',false);QV('p13bigok',false);p13dragtimer=null;", 200);
}
}
//
// FILES DOWNLOAD
//
var downloadFile; // Global state for file download
// Called by the html page to start a download, arguments are: path, file name and file size.
function p13downloadfile(x, y, z) {
if (xxdialogMode || downloadFile || !files) return;
downloadFile = { path: decodeURIComponent(x), file: decodeURIComponent(y), size: z, tsize: 0, data: '', state: 0, id: Math.random() }
//console.log('p13downloadFileCancel', downloadFile);
files.send(JSON.stringify({ action: 'download', sub: 'start', id: downloadFile.id, path: downloadFile.path }));
setDialogMode(2, "Download File", 10, p13downloadFileCancel, '<div>' + downloadFile.file + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
}
// Called by the html page to cancel the download
function p13downloadFileCancel() { setDialogMode(0); files.send(JSON.stringify({ action: 'download', sub: 'cancel', id: downloadFile.id })); downloadFile = null; }
// Called by the transport when download control command is received
function p13gotDownloadCommand(cmd) {
//console.log('p13gotDownloadCommand', cmd);
if ((downloadFile == null) || (cmd.id != downloadFile.id)) return;
if (cmd.sub == 'start') { downloadFile.state = 1; files.send(JSON.stringify({ action: 'download', sub: 'startack', id: downloadFile.id })); }
else if (cmd.sub == 'cancel') { downloadFile = null; setDialogMode(0); }
}
// Called by the transport when binary data is received
function p13gotDownloadBinaryData(data) {
if (!downloadFile || downloadFile.state == 0) return;
if (data.length > 4) {
downloadFile.tsize += (data.length - 4); // Add to the total bytes received
downloadFile.data += data.substring(4); // Append the data
Q('d2progressBar').value = downloadFile.tsize; // Change the progress bar
}
if ((ReadInt(data, 0) & 1) != 0) { // Check end flag
saveAs(data2blob(downloadFile.data), downloadFile.file); downloadFile = null; setDialogMode(0); // Save the file
} else {
files.send(JSON.stringify({ action: 'download', sub: 'ack', id: downloadFile.id })); // Send the ACK
}
}
/*
var downloadFile; // Global state for file download
// Called by the html page to start a download, arguments are: path, file name and file size.
function p13downloadfile(x, y, z) {
if (xxdialogMode) return;
downloadFile = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotDownloadData), serverPublicNamePort); // Create our websocket file transport
downloadFile.ctrlMsgAllowed = false;
downloadFile.onStateChanged = onFileDownloadStateChange;
downloadFile.xpath = decodeURIComponent(x);
downloadFile.xfile = decodeURIComponent(y);
downloadFile.xsize = z;
downloadFile.xtsize = 0;
downloadFile.xstate = 0;
downloadFile.Start(filesNode._id);
setDialogMode(2, "Download File", 10, p13downloadFileCancel, '<div>' + downloadFile.xfile + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
}
// Called by the html page to cancel the download
function p13downloadFileCancel(button, tag) {
//console.log('p13downloadFileCancel');
downloadFile.Stop();
delete downloadFile;
downloadFile = null;
}
// Called by the file transport to indicate when the transport connection state has changed
function onFileDownloadStateChange(xdownloadFile, state) {
switch (state) {
case 0: // Transport as disconnected. If this is not part of an abort, we need to save the file
setDialogMode(0); // Close any dialog boxes if present
if ((downloadFile != null) && (downloadFile.xstate == 1)) { saveAs(data2blob(downloadFile.xdata), downloadFile.xfile); } // Save the file
break;
case 3: // Transport as connected, send a command to indicate we want to start a file download
downloadFile.send(JSON.stringify({ action: 'download', reqid: 1, path: downloadFile.xpath }));
break;
}
}
// Called by the transport when data is received
function p13gotDownloadData(data) {
if (downloadFile.xstate == 0) { // If state is 0, this is a command confirming if the file will be transfered.
var cmd = JSON.parse(data);
if (cmd.action == 'downloadstart') { // Yes, the file is about to start
downloadFile.xstate = 1; // Switch to state 1, we will start receiving the file data
downloadFile.xdata = ''; // Start with empty data
downloadFile.send('a'); // Send the first ACK
} else if (cmd.action == 'downloaderror') { // Problem opening this file, cancel
p13downloadFileCancel();
}
} else { // We are in the process of receiving the file
downloadFile.xtsize += (data.length); // Add to the total bytes received
downloadFile.xdata += data; // Append the data
Q('d2progressBar').value = downloadFile.xtsize; // Change the progress bar
downloadFile.send('a'); // Send the ACK
}
}
*/
//
// FILES UPLOAD
//
var uploadFile;
function p13doUploadFiles(files) {
if (xxdialogMode) return;
uploadFile = {};
uploadFile.xpath = p13filetreelocation.join('/');
uploadFile.xfiles = files;
uploadFile.xfilePtr = -1;
setDialogMode(2, "Upload File", 10, p13uploadFileCancel, '<div id=p13dfileName>Connecting...</div><br /><progress id=d2progressBar style=width:100% value=0 max=0 />');
p13uploadReconnect();
}
function onFileUploadStateChange(xdownloadFile, state) {
switch (state) {
case 0:
p13folderup(9999);
break;
case 3:
p13uploadNextFile();
break;
}
}
// Connect again
function p13uploadReconnect() {
uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort);
uploadFile.ws.attemptWebRTC = false;
uploadFile.ws.ctrlMsgAllowed = false;
uploadFile.ws.onStateChanged = onFileUploadStateChange;
uploadFile.ws.Start(filesNode._id);
}
// Push the next file
function p13uploadNextFile() {
uploadFile.xfilePtr++;
if (uploadFile.xfiles.length > uploadFile.xfilePtr) {
uploadFile.xptr = 0;
var file = uploadFile.xfiles[uploadFile.xfilePtr];
QH('p13dfileName', file.name);
Q('d2progressBar').max = file.size;
Q('d2progressBar').value = 0;
uploadFile.xreader = new FileReader();
uploadFile.xreader.onload = function() {
uploadFile.xdata = uploadFile.xreader.result;
uploadFile.ws.send(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
};
uploadFile.xreader.readAsArrayBuffer(file);
} else {
p13uploadFileCancel();
}
}
// Used to cancel the entire transfer.
function p13uploadFileCancel(button, tag) {
if (uploadFile != null) {
if (uploadFile.ws != null) {
uploadFile.ws.Stop();
uploadFile.ws = null;
}
uploadFile = null;
}
setDialogMode(0); // Close any dialog boxes if present
}
// Receive upload ack from the mesh agent, use this to keep sending more data
function p13gotUploadData(data) {
var cmd = JSON.parse(data);
if ((uploadFile == null) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
if (cmd.action == 'uploadstart') {
p13uploadNextPart(false);
for (var i = 0; i < 8; i++) { p13uploadNextPart(true); } // Send 8 more blocks of 4 k to full the websocket.
} else if (cmd.action == 'uploadack') {
p13uploadNextPart(false);
} else if (cmd.action == 'uploaderror') {
p13uploadFileCancel();
}
}
// 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.
function p13uploadNextPart(dataPriming) {
var data = uploadFile.xdata;
var start = uploadFile.xptr;
var end = uploadFile.xptr + 4096;
if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
if (start == data.byteLength) {
if (uploadFile.ws != null) { uploadFile.ws.Stop(); uploadFile.ws = null; }
if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadReconnect(); } else { p13uploadFileCancel(); }
} else {
var datapart = data.slice(start, end);
uploadFile.ws.send(datapart);
uploadFile.xptr = end;
Q('d2progressBar').value = end;
}
}
//
// DEVICE EVENTS
//
var currentDeviceEvents = null;
function devevents_update() {
var x = '', dateHeader = null;
for (var i in currentDeviceEvents) {
var event = currentDeviceEvents[i];
var time = new Date(event.time);
if (time.toLocaleDateString() != dateHeader) {
if (dateHeader != null) x += '</table>';
x += '<table style=width:100% cellpadding=0 cellspacing=0><tr><td class=DevSt>' + time.toLocaleDateString() + '</td></tr>';
dateHeader = time.toLocaleDateString();
}
var icon = 'si3';
if (event.etype == 'user') icon = 'm2';
if (event.etype == 'server') icon = 'si3';
var msg = event.msg.split('(R)').join('&reg;');
//if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
x += '<tr><td><div class=bar18 style=height:18px;width:100%;font-size:medium>';
x += '<div style=float:left;height:18px;width:18px;background-color:white><div class=' + icon + ' style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
x += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
x += '<div style=font-size:14px><span style=width:300px>' + time.toLocaleTimeString() + ' - ' + msg + '</span></div></div></td></tr>';
}
if (dateHeader != null) x += '</table>';
if (x == '') x = "<br><i>No Events Found</i><br><br>";
QH('p16events', x);
}
/*
function showDeleteAllEventsDialog() {
if (xxdialogMode) return;
var x = "Delete all events in the server event log?<br /><br />";
x += "<input id=p3check type=checkbox onchange=validateDeleteAllEventsDialog() />Confirm";
setDialogMode(2, "Delete All Events", 3, showDeleteAllEventsDialogEx, x);
validateDeleteAllEventsDialog();
}
function validateDeleteAllEventsDialog() {
QE('idx_dlgOkButton', Q('p3check').checked);
}
function showDeleteAllEventsDialogEx(buttons, tag) {
meshserver.send({ action: 'clearevents' });
}
*/
function refreshDeviceEvents() {
//currentDeviceEvents = null;
//QH('p16events', '');
meshserver.send({ action: 'events', nodeid: currentNode._id, limit: parseInt(p16limitdropdown.value) });
}
//
// CONSOLE
//
function agentConsoleHandleKeys(e) {
var processed = 0, box = Q('p15consoleText');
if (e.key) {
if (e.keyCode == 13 && consoleFocus == 0) { p15consoleSend(e); processed = 1; }
else if (e.keyCode == 8 && consoleFocus == 0) { var x = box.value; box.value = x.substring(0, x.length - 1); processed = 1; }
else if (e.keyCode == 27) { box.value = ''; processed = 1; }
else if ((e.keyCode == 38) || (e.keyCode == 40)) { // Arrow up || Arrow down
var hindex = consoleHistory.indexOf(box.value);
//console.log(hindex, consoleHistory);
if ((e.keyCode == 38) && ((consoleHistory.length - 1) > hindex)) { box.value = consoleHistory[hindex + 1]; }
else if ((e.keyCode == 40) && (hindex > 0)) { box.value = consoleHistory[hindex - 1]; }
else if ((e.keyCode == 40) && (hindex == 0)) { box.value = ''; }
processed = 1;
}
else if (e.key.length === 1) {
//box.value = ((box.value + e.key));
insertTextAtCursor(box, e.key);
processed = 1;
}
} else {
if (e.charCode != 0 && consoleFocus == 0) { box.value = ((box.value + String.fromCharCode(e.charCode))); processed = 1; }
}
if (processed > 0) { return haltEvent(e); }
}
// Insert text at the cursor location on the
function insertTextAtCursor(ctrl, val) {
if (document.selection) { ctrl.focus(); sel = document.selection.createRange(); sel.text = val; }
else if (ctrl.selectionStart || ctrl.selectionStart == '0') {
var start = ctrl.selectionStart, end = ctrl.selectionEnd;
ctrl.value = ctrl.value.substring(0, start) + val + ctrl.value.substring(end, ctrl.value.length);
ctrl.setSelectionRange(end + 1, end + 1);
} else { ctrl.value += myValue; }
}
var consoleNode;
function setupConsole() {
// Setup the console
var samenode = (consoleNode == currentNode);
consoleNode = currentNode;
var mesh = meshes[consoleNode.meshid];
var meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
if ((meshrights & 16) != 0) {
if (consoleNode.consoleText == null) { consoleNode.consoleText = ''; }
if (samenode == false) {
QH('p15agentConsoleText', consoleNode.consoleText);
Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight;
}
var online = ((consoleNode.conn & 1) != 0)?true:false;
QH('p15statetext', online?"Mesh Agent is online":"Mesh Agent is offline");
QE('p15consoleText', online);
QE('p15uploadCore', online);
} else {
QH('p15statetext', 'Access Denied');
QE('p15consoleText', false);
QE('p15uploadCore', false);
}
}
// Clear the console for this node
function p15consoleClear() {
QH('p15agentConsoleText', '');
Q('id_p15consoleClear').blur();
consoleNode.consoleText = '';
}
// Send a command to the agent
var consoleHistory = [];
function p15consoleSend(e) {
if (e && e.keyCode != 13) return;
var v = Q('p15consoleText').value, t = '<div style=color:green>&gt; ' + EscapeHtml(Q('p15consoleText').value) + '<br/></div>';
Q('p15agentConsoleText').innerHTML += t;
consoleNode.consoleText += t;
Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight;
Q('p15consoleText').value = '';
// Send the command to the mesh agent
meshserver.send({ action: 'msg', type:'console', nodeid: consoleNode._id, value: v });
// Add command to history list
if (v.length > 0) {
// Move this command to the top if it already exists
var j = consoleHistory.indexOf(v);
if (j >= 0) { consoleHistory.splice(j, 1); }
consoleHistory.unshift(v);
consoleHistory.splice(10);
}
}
// Handle Mesh Agent console data
function p15consoleReceive(node, data) {
data = '<div>' + data + '</div>'
if (node.consoleText == null) { node.consoleText = data; } else { node.consoleText += data; }
if (consoleNode == node) {
Q('p15agentConsoleText').innerHTML += data;
Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight;
}
}
// Called then user presses the "Change Core" button
function p15uploadCore(e) {
if (xxdialogMode) return;
if (e.shiftKey == true) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, path:'*' }); } // Upload default core
else if (e.altKey == true) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id }); } // Clear the core
else if (e.ctrlKey == true) { p15uploadCore2(); } // Upload the core from a file
else { setDialogMode(2, "Change Mesh Agent Core", 3, p15uploadCoreEx, '<select id=d3coreMode style=float:right;width:260px><option value=1>Upload default server core</option><option value=2>Clear the core</option><option value=3>Upload a core file</option><option value=4>Soft disconnect agent</option><option value=5>Hard disconnect agent</option></select><div>Change Core</div>'); }
}
function p15uploadCoreEx() {
if (Q('d3coreMode').value == 1) {
// Upload default core
meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, path:'*' });
} else if (Q('d3coreMode').value == 2) {
// Clear the core
meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id });
} else if (Q('d3coreMode').value == 3) {
// Upload file as core
p15uploadCore2();
} else if (Q('d3coreMode').value == 4) {
// Soft disconnect the mesh agent
meshserver.send({ action: 'agentdisconnect', nodeid: consoleNode._id, disconnectMode: 1 });
} else if (Q('d3coreMode').value == 5) {
// Hard disconnect the mesh agent
meshserver.send({ action: 'agentdisconnect', nodeid: consoleNode._id, disconnectMode: 2 });
}
}
// Called then user opts to upload a file as core
function p15uploadCore2() {
if (xxdialogMode) return;
Q('d3localmodeform').action = 'uploadmeshcorefile.ashx';
Q('d3attrib').value = currentNode._id;
setDialogMode(3, "Upload Mesh Agent Core", 3, p15uploadCoreEx2);
d3init();
}
function p15uploadCoreEx2() {
var mode = Q('d3uploadMode').value;
if (mode == 1) {
// Upload local mesh agent core
Q('d3submit').click();
} else {
// Upload server mesh agent code
var files = d3getFileSel();
if (files.length == 1) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, path: d3filetreelocation.join('/') + '/' + files[0] }); }
}
}
//
// MY ACCOUNT
//
function account_showVerifyEmail() {
if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return;
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.";
setDialogMode(2, "Email Verification", 3, account_showVerifyEmailEx, x);
}
function account_showVerifyEmailEx() {
meshserver.send({ action: 'verifyemail', email: userinfo.email });
}
function account_showChangeEmail() {
if (xxdialogMode) return;
var x = "Change your account e-mail address here.<br /><br />";
x += addHtmlValue('Email', '<input id=dp2email style=width:230px maxlength=32 onchange=account_validateEmail() onkeyup=account_validateEmail(event) />');
setDialogMode(2, "Email Address Change", 3, account_changeEmail, x);
if (userinfo.email != null) { Q('dp2email').value = userinfo.email; }
account_validateEmail();
Q('dp2email').focus();
}
function account_validateEmail(e, email) {
var x = Q('dp2email').value.split('@');
x = (x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2) && (Q('dp2email').value.length < 1024) && (Q('dp2email').value != userinfo.email);
QE('idx_dlgOkButton', x);
if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); }
}
function account_changeEmail() {
meshserver.send({ action: 'changeemail', email: Q('dp2email').value });
}
function account_showDeleteAccount() {
if (xxdialogMode) return;
var x = "To delete this account, type in the account password in both boxes below and hit ok.<br /><br />";
x += "<form action='{{{domainurl}}}deleteaccount' method='post'><table style=margin-left:80px><tr>";
x += "<td align=right>Password:</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateDeleteAccount() onkeyup=account_validateDeleteAccount() /></td>";
x += "</tr><tr>";
x += "<td align=right>Password:</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateDeleteAccount() onkeyup=account_validateDeleteAccount() /></td>";
x += '</tr></table><br /><div style="padding:10px;margin-bottom:4px">';
x += '<input id="account_dlgCancelButton" type="button" value="Cancel" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">';
x += '<input id="account_dlgOkButton" type="submit" value="OK" style="float:right;width:80px" onclick="dialogclose(1)">';
x += '</div><br /></form>';
setDialogMode(2, "Delete Account", 0, null, x);
account_validateDeleteAccount();
Q('apassword1').focus();
}
function account_showChangePassword() {
if (xxdialogMode) return;
var x = "Change your account password by entering the new password twice in the boxes below.<br /><br />";
x += "<form action='{{{domainurl}}}changepassword' method='post'><table style=margin-left:60px><tr>";
x += "<td align=right>Password:</td><td><input id=apassword1 type=password name=apassword1 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() /> <b><span id=dxPassWarn></span></b></td>";
x += "</tr><tr>";
x += "<td align=right>Password:</td><td><input id=apassword2 type=password name=apassword2 autocomplete=off onchange=account_validateNewPassword() onkeyup=account_validateNewPassword() /></td>";
x += "</tr><tr>";
x += "<td align=right>Password Hint:</td><td><input id=apasswordhint name=apasswordhint maxlength=250 type=text autocomplete=off /></td>";
x += '</tr></table><br /><div style="padding:10px;margin-bottom:4px">';
x += '<input id=account_dlgCancelButton type=button value="Cancel" style="float:right;width:80px;margin-left:5px" onclick=dialogclose(0)>';
x += '<input id=account_dlgOkButton type=submit value="OK" style="float:right;width:80px" onclick="dialogclose(1)">';
x += '</div><br /></form>';
setDialogMode(2, "Change Password", 0, null, x);
account_validateDeleteAccount();
Q('apassword1').focus();
}
function account_createMesh() {
if (xxdialogMode) return;
var x = "Create a new mesh computer group using the options below.<br /><br />";
x += addHtmlValue('Mesh Name', '<input id=dp2meshname style=width:230px maxlength=64 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate() />');
x += addHtmlValue('Mesh Type', '<div style=width:230px;margin:0;padding:0><select id=dp2meshtype style=width:100% onchange=account_validateMeshCreate() ><option value=2>Mesh Agent Policy</option><option value=1>Intel&reg; AMT Agent-less Policy</option></select></div>');
x += addHtmlValue('Description', '<div style=width:230px;margin:0;padding:0><textarea id=dp2meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
setDialogMode(2, "Create Mesh", 3, account_createMeshEx, x);
account_validateMeshCreate();
Q('dp2meshname').focus();
}
function account_validateMeshCreate() {
QE('idx_dlgOkButton', Q('dp2meshname').value.length > 0);
}
function account_createMeshEx(button, tag) {
meshserver.send({ action: 'createmesh', meshname: Q('dp2meshname').value, meshtype: Q('dp2meshtype').value, desc: Q('dp2meshdesc').value });
}
function account_validateDeleteAccount() {
QE('account_dlgOkButton', (Q('apassword1').value.length > 0) && (Q('apassword1').value == Q('apassword2').value));
}
function account_validateNewPassword() {
QE('account_dlgOkButton', (Q('apassword1').value.length > 0) && (Q('apassword1').value == Q('apassword2').value));
var r = '';
if (Q('apassword1').value != '') {
var passStrength = checkPasswordStrength(Q('apassword1').value);
if (passStrength >= 80) { r = '<span style=color:green>Strong<span>'; } else if (passStrength >= 60) { r = '<span style=color:blue>Good<span>'; } else { r = '<span style=color:red>Weak<span>'; }
}
QH('dxPassWarn', r);
}
// Return a password strength score
function checkPasswordStrength(password) {
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) }
if (!password) return 0;
for (var i = 0; i< password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; }
for (var c in variations) { varCount += (variations[c] == true) ? 1 : 0; }
return parseInt(r + (varCount - 1) * 10);
}
function updateMeshes() {
var r = '';
var c = 0, count = 0;
for (i in meshes) {
// Mesh positioning
if (c > 1) { r += '</tr><tr>'; c = 0; }
c++;
count++;
// Mesh rights
var meshrights = meshes[i].links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
var rights = 'Partial Rights';
if (meshrights == 0xFFFFFFFF) rights = 'Full Administrator'; else if (meshrights == 0) rights = 'No Rights';
// Print the mesh information
r += '<div style=display:inline-block;width:431px;height:50px;padding-top:1px;padding-bottom:1px;float:left><div style=float:left;width:30px;height:100%></div><div style=height:100%;cursor:pointer onclick=gotoMesh(\'' + i + '\')><div class=mi style=float:left;width:50px;height:50px></div><div style=height:100%><div class=g1></div><div class=e2 style=width:300px><div class=e1>' + EscapeHtml(meshes[i].name) + '</div><div>' + rights + '</div></div><div class=g2 style=float:left></div></div></div></div>';
}
meshcount = count;
QH('p2meshes', r);
QV('p2noMeshFound', count == 0);
}
function gotoMesh(meshid) {
currentMesh = meshes[meshid];
p20updateMesh();
go(20);
}
function server_showRestoreDlg() {
if (xxdialogMode) return;
var x = 'Restore the server using a backup, <span style=color:red>this will delete the existing server data</span>. Only do this if you know what you are doing.<br /><br />';
x += '<form action="/restoreserver.ashx" enctype="multipart/form-data" method="post"><div>';
x += '<input id=account_dlgFileInput type=file name=datafile style=width:100% accept=".zip,application/octet-stream,application/zip,application/x-zip,application/x-zip-compressed" onchange=account_validateServerRestore()>';
x += '<input id=account_dlgCancelButton type=button value=Cancel style=float:right;width:80px;margin-left:5px onclick=dialogclose(0)>';
x += '<input id=account_dlgOkButton type=submit value=OK style=float:right;width:80px onclick=dialogclose(1)>';
x += '</div><br /><br /></form>';
setDialogMode(2, "Restore Server", 0, null, x);
account_validateServerRestore();
}
function account_validateServerRestore() {
QE('account_dlgOkButton', Q('account_dlgFileInput').files.length == 1);
}
function server_showVersionDlg() {
if (xxdialogMode) return;
setDialogMode(2, "MeshCentral Version", 1, null, "Loading...", 'MeshCentralServerUpdate');
meshserver.send({ action: 'serverversion' });
}
function server_showVersionDlgUpdate() { QE('idx_dlgOkButton', Q('d2updateCheck').checked); }
function server_showVersionDlgEx() { meshserver.send({ action: 'serverupdate' }); }
//
// MY MESHS
//
var currentMesh;
function p20updateMesh() {
QH('p20meshName', EscapeHtml(currentMesh.name));
var meshtype = 'Unknown #' + currentMesh.mtype;
var meshrights = currentMesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
if (currentMesh.mtype == 1) meshtype = 'Intel&reg; AMT computer group (No Agent)';
if (currentMesh.mtype == 2) meshtype = 'Mesh agent computer group';
var x = '';
x += addHtmlValue('Name', addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0));
x += addHtmlValue('Description', addLinkConditional(((currentMesh.desc && currentMesh.desc != '')?EscapeHtml(currentMesh.desc):'<i>None</i>'), 'p20editmesh(2)', (meshrights & 1) != 0));
x += addHtmlValue('Type', meshtype);
x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
x += '<br><input type=button value=Notes title="View notes about this mesh" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
x += '<br style=clear:both><br>';
var currentMeshLinks = currentMesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += '<a onclick=p20showAddMeshUserDialog() style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> Add User</a>'; }
if ((meshrights & 4) != 0) {
if (currentMesh.mtype == 1) {
x += '<a onclick=addCiraDeviceToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px title="Add a new Intel&reg; AMT computer that is located on the internet."><img src=images/icon-installmesh.png border=0 height=12 width=12> Install CIRA</a>';
x += '<a onclick=addDeviceToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px title="Add a new Intel&reg; AMT computer that is located on the local network."><img src=images/icon-installmesh.png border=0 height=12 width=12> Install local</a>';
}
if (currentMesh.mtype == 2) {
x += '<a onclick=addAgentToMesh(\"' + currentMesh._id + '\") style=cursor:pointer;margin-right:10px title="Add a new computer to this mesh by installing the mesh agent."><img src=images/icon-addnew.png border=0 height=12 width=12> Install</a>';
}
}
/*
function getMeshActions(mesh, meshrights) {
if ((meshrights & 4) == 0) return '';
var r = '';
if (mesh.mtype == 1) {
r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel&reg; AMT computer that is located on the internet." onclick=addCiraDeviceToMesh(\"' + mesh._id + '\")>Add CIRA</a>';
r += ' <a style=cursor:pointer;font-size:10px title="Add a new Intel&reg; AMT computer that is located on the local network." onclick=addDeviceToMesh(\"' + mesh._id + '\")>Add Local</a>';
}
if (mesh.mtype == 2) {
r += ' <a style=cursor:pointer;font-size:10px title="Add a new computer to this mesh by installing the mesh agent." onclick=addAgentToMesh(\"' + mesh._id + '\")>Add Agent</a>';
}
return r;
}
*/
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><th scope=col style=text-align:left></th></tr>';
var count = 1;
for (var i in currentMesh.links) {
var rights = 'Partial Rights', r = currentMesh.links[i].rights, xusername = i.split('/')[2];
if (r == 0xFFFFFFFF) rights = 'Full Administrator'; else if (r == 0) rights = 'No Rights';
var trash = '';
if ((i != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0) && (rights != 0xFFFFFFFF)))) { trash = '<a onclick=p20deleteUser(event,"' + i + '") title="Remote user rights to this mesh" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
x += '<tr onclick=p20viewuser("' + i + '") style=cursor:pointer' + (((count % 2) == 0)?';background-color:#DDD':'') + '><td><div title="Mesh User" class=m2></div><div>&nbsp;' + xusername + '<div></div></div></td><td><div style=float:right>' + trash + '</div><div>' + rights + '</div></td></tr>';
++count;
}
x += '</tbody></table>';
// If we are full administrator on this mesh, allow deletion of the mesh
if (meshrights == 0xFFFFFFFF) { x += '<div style=font-size:x-small;text-align:right><span><a onclick=p20showDeleteMeshDialog() style=cursor:pointer>Delete Mesh</a></span></div>'; }
QH('p20info', x);
}
function p20showDeleteMeshDialog() {
if (xxdialogMode) return;
var x = "Are you sure you want to delete mesh \"" + EscapeHtml(currentMesh.name) + "\"? Deleting the mesh will also delete all information about computers within this mesh.<br /><br />";
x += "<input id=p20check type=checkbox onchange=p20validateDeleteMeshDialog() />Confirm";
setDialogMode(2, "Delete Mesh", 3, p20showDeleteMeshDialogEx, x);
p20validateDeleteMeshDialog();
}
function p20validateDeleteMeshDialog() {
QE('idx_dlgOkButton', Q('p20check').checked);
}
function p20showDeleteMeshDialogEx(buttons, tag) {
meshserver.send({ action: 'deletemesh', meshid: currentMesh._id, meshname: currentMesh.name });
}
function p20editmesh(focus) {
if (xxdialogMode) return;
x = "Create a new mesh computer group using the options below.<br /><br />";
x += addHtmlValue('Mesh Name', '<input id=dp20meshname style=width:230px maxlength=32 onchange=p20editmeshValidate() onkeyup=p20editmeshValidate() />');
x += addHtmlValue('Description', '<div style=width:230px;margin:0;padding:0><textarea id=dp20meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
setDialogMode(2, "Edit Mesh", 3, p20editmeshEx, x);
Q('dp20meshname').value = currentMesh.name;
if (currentMesh.desc) Q('dp20meshdesc').value = currentMesh.desc;
p20editmeshValidate();
if (focus == 2) { Q('dp20meshdesc').focus(); } else { Q('dp20meshname').focus(); }
}
function p20editmeshEx() {
meshserver.send({ action: 'editmesh', meshid: currentMesh._id, meshname: Q('dp20meshname').value, desc: Q('dp20meshdesc').value });
}
function p20editmeshValidate() {
QE('idx_dlgOkButton', Q('dp20meshname').value.length > 0);
}
function p20showAddMeshUserDialog() {
if (xxdialogMode) return;
x = "Allow a user to manage the mesh and computers on this mesh<br /><br />";
x += addHtmlValue('User Name', '<input id=dp20username style=width:230px maxlength=32 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() />');
x += '<br><div>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20fulladmin>Full Administrator<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editmesh>Edit Mesh<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20manageusers>Manage Mesh Users<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20managecomputers>Manage Mesh Computers<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotecontrol>Remote Control<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshagentconsole>Mesh Agent Console<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshserverfiles>Server Files<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>Wake Devices<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>Edit Device Notes<br>';
x += '</div>';
setDialogMode(2, "Add User to Mesh", 3, p20showAddMeshUserDialogEx, x);
p20validateAddMeshUserDialog();
Q('dp20username').focus();
}
function p20validateAddMeshUserDialog() {
var meshrights = currentMesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
QE('idx_dlgOkButton', (Q('dp20username').value.length > 0));
QE('p20fulladmin', meshrights == 0xFFFFFFFF);
QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF));
QE('p20manageusers', !Q('p20fulladmin').checked);
QE('p20managecomputers', !Q('p20fulladmin').checked);
QE('p20remotecontrol', !Q('p20fulladmin').checked);
QE('p20meshagentconsole', !Q('p20fulladmin').checked);
QE('p20meshserverfiles', !Q('p20fulladmin').checked);
QE('p20wakedevices', !Q('p20fulladmin').checked);
QE('p20editnotes', !Q('p20fulladmin').checked);
}
function p20showAddMeshUserDialogEx() {
var meshadmin = 0;
if (Q('p20fulladmin').checked == true) { meshadmin = 0xFFFFFFFF; } else {
if (Q('p20editmesh').checked == true) meshadmin += 1;
if (Q('p20manageusers').checked == true) meshadmin += 2;
if (Q('p20managecomputers').checked == true) meshadmin += 4;
if (Q('p20remotecontrol').checked == true) meshadmin += 8;
if (Q('p20meshagentconsole').checked == true) meshadmin += 16;
if (Q('p20meshserverfiles').checked == true) meshadmin += 32;
if (Q('p20wakedevices').checked == true) meshadmin += 64;
if (Q('p20editnotes').checked == true) meshadmin += 128;
}
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value , meshadmin: meshadmin});
}
function p20viewuser(userid) {
if (xxdialogMode) return;
var cmeshrights = currentMesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
var meshrights = currentMesh.links[userid].rights;
var r = '';
if (meshrights == 0xFFFFFFFF) r = ', Full Administrator (all rights)'; else {
if ((meshrights & 1) != 0) r += ', Edit Mesh';
if ((meshrights & 2) != 0) r += ', Manage Mesh Users';
if ((meshrights & 4) != 0) r += ', Manage Mesh Computers';
if ((meshrights & 8) != 0) r += ', Remote Control';
if ((meshrights & 16) != 0) r += ', Agent Console';
if ((meshrights & 32) != 0) r += ', Server Files';
if ((meshrights & 64) != 0) r += ', Wake Devices';
if ((meshrights & 128) != 0) r += ', Edit Notes';
}
r = r.substring(2);
if (r == '') { r = 'No Rights'; }
var x = addHtmlValue('User Name', userid.split('/')[2]);
x += addHtmlValue('Permissions', r);
var buttons = 1;
if ((('user/{{{domain}}}/' + userinfo.name.toLowerCase()) != userid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) buttons += 4;
setDialogMode(2, "Mesh User", buttons, p20viewuserEx, x, userid);
}
function p20viewuserEx(button, userid) {
if (button != 2) return;
setDialogMode(2, "Remote Mesh User", 3, p20viewuserEx2, "Confirm removal of user " + userid.split('/')[2] + "?", userid);
}
function p20deleteUser(e, userid) {
haltEvent(e);
p20viewuserEx(2, userid);
}
function p20viewuserEx2(button, userid) {
meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid});
}
//
// MY FILES
//
var filetreelinkpath;
var filetreelocation = [];
function updateFiles() {
QV('MainMenuMyFiles', ((features & 8) == 0));
if ((features & 8) != 0) return; // If running on a server without files, exit now.
var html1 = '', html2 = '', displayPath = '<a style=cursor:pointer onclick=p5folderup(0)>Root</a>', fullPath = 'Root', publicPath, filetreex = filetree, folderdepth = 1;
// Navigate to path location, build the paths at the same time
var filetreelocation2 = [], oldlinkpath = filetreelinkpath, checkedBoxes = [], checkboxes = document.getElementsByName('fc');
for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedBoxes.push(checkboxes[i].value) }; } // Save all existing checked boxes
filetreelinkpath = '';
for (var i in filetreelocation) {
if ((filetreex.f != null) && (filetreex.f[filetreelocation[i]] != null)) {
filetreelocation2.push(filetreelocation[i]);
fullPath += ' / ' + filetreelocation[i];
if ((folderdepth == 1)) {
var sp = filetreelocation[i].split('/');
publicPath = window.location + sp[0] + 'files/' + sp[2];
//if (filetreelocation[i] === userinfo._id) { filetreelinkpath += 'self'; } else { filetreelinkpath += (sp[0] + '/' + sp[2]); }
filetreelinkpath += filetreelocation[i];
} else {
if (filetreelinkpath != '') { filetreelinkpath += '/' + filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + filetreelocation[i]; } }
}
filetreex = filetreex.f[filetreelocation[i]];
displayPath += ' / <a style=cursor:pointer onclick=p5folderup(' + folderdepth + ')>' + (filetreex.n != null?filetreex.n:filetreelocation[i]) + '</a>';
folderdepth++;
} else {
break;
}
}
filetreelocation = filetreelocation2; // In case we could not go down the full path, we set the new path location here.
var publicfolder = fullPath.toLowerCase().startsWith("root / " + userinfo._id + " / public");
// Sort the files
var filetreexx = p5sort_files(filetreex.f);
// Display all files and folders at this location
for (var i in filetreexx) {
// Figure out the name and shortname
var f = filetreexx[i], name = f.n, shortname;
shortname = name;
if (name.length > 70) { shortname = '<span title="' + EscapeHtml(name) + '">' + EscapeHtml(name.substring(0, 70)) + "...</span>"; } else { shortname = EscapeHtml(name); }
name = EscapeHtml(name);
// Figure out the date
var fdatestr = '';
if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + "/" + (fdate.getDate()) + "/" + fdate.getFullYear() + " " + fdate.toLocaleTimeString() + "&nbsp;"; }
// Figure out the size
var fsize = '';
if (f.s != null) { fsize = getFileSizeStr(f.s); }
var h = '';
if (f.t < 3) {
var right = (f.t == 1)?p5getQuotabar(f):'', title = '';
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 title=\"" + title + "\">" + right + "</span><span><div class=fileIcon" + f.t + "></div><a style=cursor:pointer onclick=p5folderset(\"" + encodeURIComponent(f.nx) + "\")>" + shortname + "</a></span></div>";
} else {
var link = shortname;
var publiclink = '';
if (publicfolder) { publiclink = ' (<a style=cursor:pointer title=\"Display public link\" onclick=\'p5showPublicLink(\"' + publicPath + '/' + f.nx + '\")\'>Link</a>)'; }
if (f.s > 0) { link = "<a target=\"_blank\" href=\"downloadfile.ashx?link=" + encodeURIComponent(filetreelinkpath + '/' + f.nx) + "\">" + shortname + "</a>" + publiclink; }
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 class=fsize>" + fdatestr + "</span><span style=float:right>" + fsize + "</span><span><div class=fileIcon" + f.t + "></div>" + link + "</span></div>";
}
if (f.t < 3) { html1 += h; } else { html2 += h; }
}
//if (f.parent == null) { }
QH('p5rightOfButtons', p5getQuotabar(filetreex));
QH('p5files', html1 + html2);
QH('p5currentpath', displayPath);
QE('p5FolderUp', filetreelocation.length != 0);
QV('p5PublicShare', publicfolder);
// Re-check all boxes if needed
if (oldlinkpath == filetreelinkpath) {
checkboxes = document.getElementsByName('fc');
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].checked = (checkedBoxes.indexOf(checkboxes[i].value) >= 0);
}
}
p5setActions();
}
function p5getQuotabar(f) {
while (f.t > 1) { f = f.parent; }
if ((f.t != 1) || (f.maxbytes == null)) return '';
var tf = Math.floor(f.s / 1024), tq = Math.floor((f.maxbytes - f.s) / 1024);
return '<span title="' + tf + "k in " + f.c + " file" + (f.c > 1?'s':'') + ". " + (Math.floor(f.maxbytes / 1024)) + 'k maxinum">' + ((tq < 0)?('Storage limit exceed'):(tq + 'k remaining')) + ' <progress style=height:10px;width:100px value=' + f.s + ' max=' + f.maxbytes + ' /></span>';
}
function p5showPublicLink(u) { setDialogMode(2, "Public Link", 1, null, '<input type=text style=width:100% value="' + u + '" readonly />'); }
var sortorder;
function p5sort_filename(a, b) { if (a.ln > b.ln) return (1 * sortorder); if (a.ln < b.ln) return (-1 * sortorder); return 0; }
function p5sort_timestamp(a, b) { if (a.d > b.d) return (1 * sortorder); if (a.d < b.d) return (-1 * sortorder); return 0; }
function p5sort_bysize(a, b) { if (a.s == b.s) return p5sort_filename(a, b); return (((a.s - b.s)) * sortorder); }
function p5sort_files(files) {
var r = [], sortselection = Q('p5sortdropdown').value;
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]); }
sortorder = 1;
if (sortselection > 3) { sortorder = -1; sortselection -= 3; }
if (sortselection == 1) { r.sort(p5sort_filename); }
else if (sortselection == 2) { r.sort(p5sort_bysize); }
else if (sortselection == 3) { r.sort(p5sort_timestamp); }
return r;
}
function p5setActions() {
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)
QE('p5DeleteFileButton', (cc > 0) && (filetreelocation.length > 0));
QE('p5NewFolderButton', filetreelocation.length > 0);
QE('p5UploadButton', filetreelocation.length > 0);
QE('p5RenameFileButton', (cc == 1) && (filetreelocation.length > 0));
QE('p5SelectAllButton', tc > 0);
Q('p5SelectAllButton').value = (cc > 0 ? 'Select None' : 'Select All');
QE('p5CutButton', (sfc > 0) && (cc == sfc));
QE('p5CopyButton', (sfc > 0) && (cc == sfc));
QE('p5PasteButton', (p5clipboard != null) && (p5clipboard.length > 0));
}
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; }
function getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fc'); return checkboxes.length; }
function p5selectallfile() { var nv = (getFileSelCount() == 0), checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p5setActions(); }
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; }
function getFileSizeStr(size) { if (size == 1) return "1 byte"; return "" + size + " bytes"; }
function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); }
function p5folderset(x) { filetreelocation.push(decodeURIComponent(x)); updateFiles(); }
function p5createfolder() { setDialogMode(2, "New Folder", 3, p5createfolderEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck(event) style=width:100% />'); focusTextBox('p5renameinput'); p5fileNameCheck(); }
function p5createfolderEx() { meshserver.send({ action: 'fileoperation', fileop: 'createfolder', path: filetreelocation, newfolder: Q('p5renameinput').value}); }
function p5deletefile() { var cc = getFileSelCount(); setDialogMode(2, "Delete", 3, p5deletefileEx, (cc > 1)?('Delete ' + cc + ' selected items?'):('Delete selected item?')); }
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}); }
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(); }
function p5renamefileEx(b, t) { t.newname = Q('p5renameinput').value; meshserver.send(t); }
function p5fileNameCheck(e) { var x = isFilenameValid(Q('p5renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e.keyCode == 13)) { dialogclose(1); } }
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] != '.'); } })();
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=submit id=p5loginSubmit style=display:none /></form>'); updateUploadDialogOk('p5uploadinput'); }
function p5uploadFileEx() { Q('p5loginSubmit').click(); }
function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
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(); }
function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Confim ' + (p5clipboardCut == 0?'copy':'move') + ' of ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1)?'s':'') + ' to this location?' } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
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(); } }
function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Holding ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1)?'s':'') + ' for ' + (p5clipboardCut == 0?'copy':'move') + ', <a onclick=p5clearClip() style=cursor:pointer>Clear</a>.' } QH('p5bottomstatus', x); p5setActions(); }
function p5clearClip() { p5clipboard = null; p5clipboardFolder = null; p5clipboardCut = 0; p5updateClipview(); }
function p5fileDragDrop(e) {
haltEvent(e);
QV('bigfail', false);
QV('bigok', false);
//QV('p5fileCatchAllInput', false);
if (e.dataTransfer == null || e.dataTransfer.files.length == 0 || filetreelocation.length == 0) return;
var names = [], sizes = [], types = [], datas = [], readercount = e.dataTransfer.files.length;
for (var i = 0; i < e.dataTransfer.files.length; i++) {
var reader = new FileReader(), file = e.dataTransfer.files[i];
names.push(file.name);
sizes.push(file.size);
types.push(file.type);
reader.onload = function(event) {
datas.push(event.target.result);
if (--readercount == 0) {
Q('p5fileDragName').value = names.join('*');
Q('p5fileDragSize').value = sizes.join('*');
Q('p5fileDragType').value = types.join('*');
Q('p5fileDragData').value = datas.join('*');
Q('p5fileDragLink').value = encodeURIComponent(filetreelinkpath);
Q('p5loginSubmit2').click();
}
}
reader.readAsDataURL(file);
}
}
var p5dragtimer = null;
function p5fileDragOver(e) {
haltEvent(e);
if (p5dragtimer != null) { clearTimeout(p5dragtimer); p5dragtimer = null; }
var ac = true; // TODO: Set to true if we can accept the file
if (filetreelocation.length == 0) { ac = false; }
QV('bigok', ac);
QV('bigfail', !ac);
//QV('p5fileCatchAllInput', ac);
}
function p5fileDragLeave(e) {
haltEvent(e);
if (e.target.id != "p5filetable") {
QV('bigfail', false);
QV('bigok', false);
//QV('p5fileCatchAllInput', false);
} else {
p5dragtimer = setTimeout("QV('bigfail',false);QV('bigok',false);p5dragtimer=null;", 200);
}
}
/*
function p5fileCatchAllInputChanged(e) {
p5fileDragLeave(e);
Q('p5fileDragLink2').value = encodeURIComponent(filetreelinkpath);
Q('p5fileCatchAllSubmit').click();
}
*/
//
// MY EVENTS
//
function events_update() {
var x = '', dateHeader = null;
for (var i in events) {
var event = events[i];
var time = new Date(event.time);
if (time.toLocaleDateString() != dateHeader) {
if (dateHeader != null) x += '</table>';
x += '<table style=width:100% cellpadding=0 cellspacing=0><tr><td class=DevSt>' + time.toLocaleDateString() + '</td></tr>';
dateHeader = time.toLocaleDateString();
}
var icon = 'si3';
if (event.etype == 'user') icon = 'm2';
if (event.etype == 'server') icon = 'si3';
var msg = event.msg.split('(R)').join('&reg;');
if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
x += '<tr><td><div class=bar18 style=height:18px;width:100%;font-size:medium>';
x += '<div style=float:left;height:18px;width:18px;background-color:white><div class=' + icon + ' style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
x += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
x += '<div style=font-size:14px><span style=width:300px>' + time.toLocaleTimeString() + ' - ' + msg + '</span></div></div></td></tr>';
}
if (dateHeader != null) x += '</table>';
if (x == '') x = "<br><i>No Events Found</i><br><br>";
QH('p3events', x);
}
function showDeleteAllEventsDialog() {
if (xxdialogMode) return;
var x = "Delete all events in the server event log?<br /><br />";
x += "<input id=p3check type=checkbox onchange=validateDeleteAllEventsDialog() />Confirm";
setDialogMode(2, "Delete All Events", 3, showDeleteAllEventsDialogEx, x);
validateDeleteAllEventsDialog();
}
function validateDeleteAllEventsDialog() {
QE('idx_dlgOkButton', Q('p3check').checked);
}
function showDeleteAllEventsDialogEx(buttons, tag) {
meshserver.send({ action: 'clearevents' });
}
function refreshEvents() {
meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
}
//
// MY USERS
//
function updateUsers() {
QV('MainMenuMyUsers', (users != null) && ((features & 4) == 0));
if ((users == null) || ((features & 4) != 0)) { QH('p3users', ''); return; }
// Sort the list of user id's
var sortedUserIds = [];
for (var i in users) { sortedUserIds.push(i); }
sortedUserIds.sort();
// Display the users using the sorted list
var x = '<table style=width:100% cellpadding=0 cellspacing=0>', addHeader = true;
// Online users
for (var i in sortedUserIds) {
var user = users[sortedUserIds[i]], sessions = null;
if (wssessions != null) { sessions = wssessions[user._id]; }
if (sessions != null) {
if (addHeader) { x += '<tr><td style="border-bottom:1pt solid lightgray;padding-top:4px;padding-bottom:4px">Online Users</td></tr>'; addHeader = false; }
x += addUserHtml(user, sessions);
}
}
addHeader = true;
// Offline users
for (var i in sortedUserIds) {
var user = users[sortedUserIds[i]], sessions = null;
if (wssessions != null) { sessions = wssessions[user._id]; }
if (sessions == null) {
if (addHeader) { x += '<tr><td style="border-bottom:1pt solid lightgray;padding-top:4px;padding-bottom:4px">Offline Users</td></tr>'; addHeader = false; }
x += addUserHtml(user, sessions);
}
}
x += '</table>';
QH('p3users', x);
// Update current user panel if needed
if ((currentUser != null) && (xxcurrentView == 30)) { gotoUser(encodeURIComponent(currentUser._id),true); }
}
function addUserHtml(user, sessions) {
var x = '', gray = ' gray', icon = 'm2', msg = '', self = (user.name != userinfo.name);
if (sessions != null) {
gray = '';
if (self) { msg += "<a onclick=showUserAlertDialog(event,\"" + encodeURIComponent(user._id) + "\")>"; }
if (sessions == 1) { msg += '1 active session'; } else { msg += sessions + ' active sessions'; }
if (self) { msg += "</a>"; }
} else {
if (user.login) { msg += '<span title="Last login: ' + new Date(user.login).toLocaleString() + '">' + new Date(user.login).toLocaleDateString() + '</span>'; }
}
if (msg != '') msg += ', ';
if (self) { msg += "<a onclick=showUserAdminDialog(event,\"" + encodeURIComponent(user._id) + "\")>"; }
if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { msg += "Locked, "; }
msg += "<span title='Server Permissions'>";
if ((user.siteadmin == null) || (user.siteadmin == 0) || (user.siteadmin == 32)) {
msg += "User";
} else if (user.siteadmin == 8) {
msg += "User with server files";
} else if (user.siteadmin == 0xFFFFFFFF) {
msg += "Administrator";
} else {
msg += "Partial";
}
msg += "</span>";
if ((user.quota != null) && ((user.siteadmin & 8) != 0)) { msg += ", " + (user.quota / 1024) + " k"; }
if (self) { msg += "</a>"; }
var username = EscapeHtml(user.name), emailVerified = '';
if (serverinfo.emailcheck == true) { emailVerified = ((user.emailVerified != true)?' <b style=color:red title="Email is not verified">&#x1F5F4</b>':' <b style=color:green title="Email is verified">&#x1F5F8</b>'); }
if (user.email != null) { username += ', <a onclick=doemail(event,\"' + user.email + '\")>' + user.email + '</a>' + emailVerified; }
x += '<tr><td style=cursor:pointer onclick=gotoUser(\"' + encodeURIComponent(user._id) + '\")>';
x += '<div class=bar style=height:24px;width:100%;font-size:medium>';
x += '<div style=float:left;height:24px;width:24px;background-color:white><div class="' + icon + gray + '" style=width:16px;margin-top:4px;margin-left:2px;height:16px></div></div>';
x += '<div class=g1 style=height:24px;float:left></div><div class=g2 style=height:24px;float:right></div>';
x += '<div><span>' + username + '</span><span style=float:right>' + msg + '</span></div></div></td></tr>';
return x;
}
function showUserAlertDialog(e, userid) {
if (xxdialogMode) return;
haltEvent(e);
setDialogMode(2, "Notify " + EscapeHtml(users[decodeURIComponent(userid)].name), 3, showUserAlertDialogEx, 'Send a text notification to this user.<textarea id=d2notifyText maxlength=2048 style="width:100%;height:184px;resize:none"></textarea>', userid);
Q('d2notifyText').focus();
return false;
}
function showUserAlertDialogEx(button, userid) { meshserver.send({ action: 'notifyuser', userid: decodeURIComponent(userid), msg: Q('d2notifyText').value }); }
function doemail(e, addr) {
if (xxdialogMode) return;
haltEvent(e);
window.open("mailto:" + addr);
return false;
}
function showCreateNewAccountDialog() {
if (xxdialogMode) return;
var x = '';
x += addHtmlValue('Name', '<input id=p4name style=width:230px maxlength=64 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
x += addHtmlValue('Email', '<input id=p4email style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
x += addHtmlValue('Password', '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
setDialogMode(2, "Create Account", 3, showCreateNewAccountDialogEx, x);
showCreateNewAccountDialogValidate();
Q('p4name').focus();
}
function showCreateNewAccountDialogValidate() {
QE('idx_dlgOkButton', (!Q('p4name') || (Q('p4name').value.length > 0)) && Q('p4pass1').value.length > 0 && Q('p4pass1').value == Q('p4pass2').value);
}
function showCreateNewAccountDialogEx() {
meshserver.send({ action: 'adduser', username: Q('p4name').value, email: Q('p4email').value, pass: Q('p4pass1').value });
}
function showUserAdminDialog(e, userid) {
if (xxdialogMode) return;
haltEvent(e);
userid = decodeURIComponent(userid);
var x = '<div>';
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_fileaccess>Server Files, <input type=number onchange=showUserAdminDialogValidate() maxlength=10 style=width:80px;text-align:right id=ua_fileaccessquota>k max, blank for default<br><hr/>';
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_fulladmin>Full Administrator<br>';
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_serverbackup>Server Backup<br>';
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_serverrestore>Server Restore<br>';
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_serverupdate>Server Updates<br>';
x += '<input type=checkbox onchange=showUserAdminDialogValidate() id=ua_manageusers>Manage Users<br>';
x += '<hr/><input type=checkbox onchange=showUserAdminDialogValidate() id=ua_lockedaccount>Lock Account<br>';
x += '</div>';
var user = users[userid.toLowerCase()];
setDialogMode(2, "Server Permissions", 3, showUserAdminDialogEx, x, user);
if (user.siteadmin && user.siteadmin != 0) {
Q('ua_fulladmin').checked = (user.siteadmin == 0xFFFFFFFF);
Q('ua_serverbackup').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1) != 0)); // Server Backup
Q('ua_manageusers').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 2) != 0)); // Manage Users
Q('ua_serverrestore').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 4) != 0)); // Server Restore
Q('ua_fileaccess').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 8) != 0)); // Server Files
Q('ua_serverupdate').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 16) != 0)); // Server Update
Q('ua_lockedaccount').checked = ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 32) != 0)); // Account locked
}
QE('ua_fulladmin', userinfo.siteadmin == 0xFFFFFFFF);
QE('ua_serverbackup', userinfo.siteadmin == 0xFFFFFFFF);
QE('ua_manageusers', userinfo.siteadmin == 0xFFFFFFFF);
QE('ua_serverrestore', userinfo.siteadmin == 0xFFFFFFFF);
QE('ua_fileaccess', userinfo.siteadmin == 0xFFFFFFFF);
QE('ua_serverupdate', userinfo.siteadmin == 0xFFFFFFFF);
Q('ua_fileaccessquota').value = (user.quota != null)?(user.quota / 1024):'';
showUserAdminDialogValidate();
return false;
}
function showUserAdminDialogValidate() {
if (userinfo.siteadmin == 0xFFFFFFFF) {
QE('ua_serverbackup', !Q('ua_fulladmin').checked);
QE('ua_manageusers', !Q('ua_fulladmin').checked);
QE('ua_serverrestore', !Q('ua_fulladmin').checked);
QE('ua_fileaccess', !Q('ua_fulladmin').checked);
QE('ua_serverupdate', !Q('ua_fulladmin').checked);
QE('ua_fileaccessquota', Q('ua_fileaccess').checked && !Q('ua_fulladmin').checked);
}
}
function showUserAdminDialogEx(button, user) {
var siteadmin = 0, quota = parseInt(Q('ua_fileaccessquota').value);
if (Q('ua_fulladmin').checked == true) { siteadmin = 0xFFFFFFFF; } else {
if (Q('ua_serverbackup').checked == true) siteadmin += 1;
if (Q('ua_manageusers').checked == true) siteadmin += 2;
if (Q('ua_serverrestore').checked == true) siteadmin += 4;
if (Q('ua_fileaccess').checked == true) siteadmin += 8;
if (Q('ua_serverupdate').checked == true) siteadmin += 16;
if (Q('ua_lockedaccount').checked == true) siteadmin += 32;
}
var x = { action: 'edituser', name: user.name, siteadmin: siteadmin };
if (isNaN(quota) == false) { x.quota = (quota * 1024); }
meshserver.send(x);
}
//
// MY USERS GENERAL
//
var currentUser = null;
function gotoUser(userid, force) {
if (xxdialogMode && !force) return;
var user = currentUser = users[decodeURIComponent(userid)];
if (user == null) { setDialogMode(0); go(4); return; }
QH('p30userName', user.name);
QH('p31userName', user.name);
var self = (user.name == userinfo.name), activeSessions = 0;
if (wssessions != null && wssessions[user._id]) { activeSessions = wssessions[user._id]; }
// Change user grayscale
Q('MainUserImage').classList.remove('gray');
if (activeSessions == 0) { Q('MainUserImage').classList.add('gray'); }
// Server permissions
var msg = '';
if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { msg += "Locked account, "; }
if ((user.siteadmin == null) || (user.siteadmin == 0) || (user.siteadmin == 32)) { msg += "No server rights"; } else if (user.siteadmin == 8) { msg += "Access to server files"; } else if (user.siteadmin == 0xFFFFFFFF) { msg += "Full administrator"; } else { msg += "Partial rights"; }
// Show user attributes
var x = '<div style=min-height:80px><table style=width:100%>';
var email = user.email?EscapeHtml(user.email):'<i>Not set</i>', everify = '';
if (serverinfo.emailcheck) { everify = ((user.emailVerified == true)?'<b style=color:green;cursor:pointer title="Email is verified">&#x1F5F8</b> ':'<b style=color:red;cursor:pointer title="Email not verified">&#x1F5F4</b> '); }
x += addDeviceAttribute('Email', everify + "<a style=cursor:pointer onclick=p30showUserEmailChangeDialog(event,\"" + userid + "\")>" + email + '</a> <a style=cursor:pointer onclick=doemail(event,\"' + user.email + '\")><img src="images/link1.png" /></a>');
x += addDeviceAttribute('Server Rights', "<a style=cursor:pointer onclick=showUserAdminDialog(event,\"" + userid + "\")>" + msg + "</a>");
if (user.quota) x += addDeviceAttribute('Server Quota', EscapeHtml(parseInt(user.quota) / 1024) + ' k');
x += addDeviceAttribute('Creation', new Date(user.creation).toLocaleString());
if (user.login) x += addDeviceAttribute('Last Login', new Date(user.login).toLocaleString());
x += '</table></div><br />';
// Add action buttons
x += '<input type=button value=Notes title="View notes about this user" onclick=showNotes(false,"' + userid + '") />';
if (!self && (activeSessions > 0)) { x += '<input type=button value=Notify title="Send user notification" onclick=showUserAlertDialog(event,"' + userid + '") />'; }
// Setup the panel
QH('p30html', x);
// Draw the user timeline
drawUserTimeline();
// Check if we can delete this user
var deletePossible = true;
if (user._id == userinfo._id) deletePossible = false;
if (user.siteadmin && user.siteadmin > 0 && userinfo.siteadmin != 0xFFFFFFFF) deletePossible = false;
// Show bottom buttons
x = '<div style=float:right;font-size:x-small>';
if (deletePossible) x += '<a style=cursor:pointer onclick=p30showDeleteUserDialog() title="Remove this user">Delete User</a>';
x += '</div><div style=font-size:x-small>';
if (userinfo.siteadmin == 0xFFFFFFFF) x += '<a style=cursor:pointer onclick=p30showUserChangePassDialog() title="Change the password for this user">Change Password</a>';
x += '</div><br>'
QH('p30html3', x);
// Update user's connection state
x = '';
if (activeSessions == 1) { x = '1 active session'; } else if (activeSessions > 1) { x = activeSessions + ' active sessions'; }
QH('MainUserState', x);
go(30);
// Update user events (TODO: do this only if we change users)
QH('p31events', '');
refreshUsersEvents();
}
// Display the user's email change dialog box
function p30showUserEmailChangeDialog(event) {
if (xxdialogMode) return;
var x = '';
x += addHtmlValue('Email', '<input id=dp30email style=width:230px maxlength=32 onchange=p30validateEmail() onkeyup=p30validateEmail() />');
if (serverinfo.emailcheck) { x += addHtmlValue('Status', '<select id=dp30verified style=width:230px onchange=p30validateEmail()><option value=0>Not verified</option><option value=1>Verified</option></select>'); }
setDialogMode(2, "Change Email for " + EscapeHtml(currentUser.name), 3, p30showUserEmailChangeDialogEx, x);
Q('dp30email').focus();
Q('dp30email').value = currentUser.email;
if (serverinfo.emailcheck) { Q('dp30verified').value = currentUser.emailVerified?1:0; }
p30validateEmail();
}
// Perform validation on the user's email change dialog box
function p30validateEmail() {
var v = Q('dp30email').value, x = v.split('@');
x = (x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2) && (v.length < 1024) && ((v != userinfo.email) || ((serverinfo.emailcheck == true) && (Q('dp30verified').value != (userinfo.emailVerified?1:0))));
QE('idx_dlgOkButton', x);
}
// Send to the server the new user's email address and validation status
function p30showUserEmailChangeDialogEx() {
var x = { action: 'edituser', name: currentUser.name, email: Q('dp30email').value };
if (serverinfo.emailcheck) { x.emailVerified = (Q('dp30verified').value == 1); }
meshserver.send(x);
}
// Display the user's password change dialog box
function p30showUserChangePassDialog() {
if (xxdialogMode) return;
var x = '';
x += addHtmlValue('Password', '<input id=p4pass1 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=256 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
setDialogMode(2, "Change Password for " + EscapeHtml(currentUser.name), 3, p30showUserChangePassDialogEx, x);
showCreateNewAccountDialogValidate();
Q('p4pass1').focus();
}
function p30showUserChangePassDialogEx() {
if (Q('p4pass1').value == Q('p4pass2').value) { meshserver.send({ action: 'changeuserpass', user: currentUser.name, pass: Q('p4pass1').value }); } }
function p30showDeleteUserDialog() {
if (xxdialogMode) return;
setDialogMode(2, "Delete User " + EscapeHtml(currentUser.name), 3, p30showDeleteUserDialogEx, 'Confirm deletion of user ' + EscapeHtml(currentUser.name) + '?');
}
function p30showDeleteUserDialogEx() {
meshserver.send({ action: 'deleteuser', userid: currentUser._id, username: currentUser.name });
}
// Draw device power bars. The bars are 766px wide.
function drawUserTimeline() {
var timeline = null, now = Date.now();
//if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
timeline = [];
// Calculate when the timeline starts
var d = new Date();
d.setHours(0, 0, 0, 0);
d = new Date(d.getTime() - (1000 * 60 * 60 * 24 * 6));
var timelineStart = d.getTime();
// De-compact the timeline
var timeline2 = [];
if (timeline != null && timeline.length > 1) {
timeline2.push([ 0, timeline[1], timeline[0] ]); // Start, End, Power
var ct = timeline[1];
for (var i = 2; i < timeline.length; i += 2) {
var power = timeline[i], dt = now;
if (timeline.length > (i + 1)) { dt = timeline[i + 1]; }
timeline2.push([ ct, ct + dt, power ]); // Start, End, Power
ct = ct + dt;
}
}
// Draw the timeline
var x = '', count = 1, date = new Date();
date.setHours(0, 0, 0, 0);
for (var i = 0; i < 7; i++) {
var datavalue = '', start = date.getTime(), end = start + (1000 * 60 * 60 * 24);
for (var j in timeline2) {
var block = timeline2[j];
if (isTimeBlockInside(start, end, block[0], block[1]) == true) {
var ts = Math.max(start, block[0]);
var te = Math.min(Math.min(end, block[1]), now);
var width = Math.round((te - ts) / 112794);
if (width > 0) {
var title = powerStateStrings2[block[2]] + ' from ' + new Date(ts).toLocaleTimeString() + ' to ' + new Date(te).toLocaleTimeString() + '.';
datavalue += '<div title="' + title + '" style=display:table-cell;width:' + width + 'px;background-color:' + powerColor(block[2]) + ';height:16px></div>';
}
}
}
x += '<tr style=' + (((count % 2) == 0)?'background-color:#DDD':'') + '><td><div>&nbsp;' + date.toLocaleDateString() + '<div></div></div></td><td><div>' + datavalue + '</div></td></tr>';
++count;
date = new Date(date.getTime() - (1000 * 60 * 60 * 24)); // Substract one day
}
QH('p30html2', '<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:center;width:150px>Day</th><th scope=col style=text-align:center>7 Day Login State</th></tr>' + x + '</tbody></table>');
}
//
// MY USERS EVENTS
//
var currentUserEvents = null;
function userEvents_update() {
var x = '', dateHeader = null;
for (var i in currentUserEvents) {
var event = currentUserEvents[i];
var time = new Date(event.time);
if (time.toLocaleDateString() != dateHeader) {
if (dateHeader != null) x += '</table>';
x += '<table style=width:100% cellpadding=0 cellspacing=0><tr><td class=DevSt>' + time.toLocaleDateString() + '</td></tr>';
dateHeader = time.toLocaleDateString();
}
var icon = 'si3';
if (event.etype == 'user') icon = 'm2';
if (event.etype == 'server') icon = 'si3';
var msg = event.msg.split('(R)').join('&reg;');
if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
x += '<tr><td><div class=bar18 style=height:18px;width:100%;font-size:medium>';
x += '<div style=float:left;height:18px;width:18px;background-color:white><div class=' + icon + ' style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
x += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
x += '<div style=font-size:14px><span style=width:300px>' + time.toLocaleTimeString() + ' - ' + msg + '</span></div></div></td></tr>';
}
if (dateHeader != null) x += '</table>';
if (x == '') x = "<br><i>No Events Found</i><br><br>";
QH('p31events', x);
}
function refreshUsersEvents() {
meshserver.send({ action: 'events', limit: parseInt(p31limitdropdown.value), user: currentUser.name });
}
//
// FILE SELECTOR, DIALOG 3
//
function d3init() {
Q('d3localFile').value = '';
d3modechange();
}
function d3modechange() {
var mode = Q('d3uploadMode').value;
QV('d3localmode', mode == 1);
QV('d3servermode', mode == 2);
if (mode == 1) { d3setActions(); } else { d3updatefiles(); }
}
var d3filetreelinkpath;
var d3filetreelocation = [];
function d3updatefiles() {
if (Q('d3uploadMode').value == 1) return;
var html1 = '', html2 = '', filetreex = filetree, folderdepth = 1;
// Navigate to path location, build the paths at the same time
var d3filetreelocation2 = [], oldlinkpath = d3filetreelinkpath, checkedBoxes = [], checkboxes = document.getElementsByName('fc');
for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedBoxes.push(checkboxes[i].value) }; } // Save all existing checked boxes
d3filetreelinkpath = '';
for (var i in d3filetreelocation) {
if ((filetreex.f != null) && (filetreex.f[d3filetreelocation[i]] != null)) {
d3filetreelocation2.push(d3filetreelocation[i]);
if ((folderdepth == 1)) {
var sp = d3filetreelocation[i].split('/');
publicPath = window.location + sp[0] + 'files/' + sp[2];
if (d3filetreelocation[i] === userinfo._id) { d3filetreelinkpath += 'self'; } else { d3filetreelinkpath += (sp[0] + '/' + sp[2]); }
} else {
if (d3filetreelinkpath != '') { d3filetreelinkpath += '/' + d3filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + d3filetreelocation[i]; } }
}
filetreex = filetreex.f[d3filetreelocation[i]];
folderdepth++;
} else {
break;
}
}
d3filetreelocation = d3filetreelocation2; // In case we could not go down the full path, we set the new path location here.
// Sort the files
var filetreexx = p5sort_files(filetreex.f);
// Display all files and folders at this location
for (var i in filetreexx) {
// Figure out the name and shortname
var f = filetreexx[i], name = f.n, shortname;
shortname = name;
if (name.length > 70) { shortname = '<span title="' + EscapeHtml(name) + '">' + EscapeHtml(name.substring(0, 70)) + "...</span>"; } else { shortname = EscapeHtml(name); }
name = EscapeHtml(name);
// Figure out the size
var fsize = '';
if (f.s != null) { fsize = getFileSizeStr(f.s); }
var h = '';
if (f.t < 3) {
var title = '';
h = "<div class=filelist file=999><span style=float:right title=\"" + title + "\"></span><span><div class=fileIcon" + f.t + "></div>&nbsp;<a style=cursor:pointer onclick=d3folderset(\"" + encodeURIComponent(f.nx) + "\")>" + shortname + "</a></span></div>";
} else {
var link = shortname;
//if (f.s > 0) { link = "<a target=\"_blank\" href=\"downloadfile.ashx?link=" + encodeURIComponent(filetreelinkpath + '/' + f.nx) + "\">" + shortname + "</a>"; }
h = "<div class=filelist file=3><input style=float:left name=fcx class=fcb type=checkbox onchange=d3setActions() value='" + f.nx + "'>&nbsp;<span style=float:right>" + fsize + "</span><span><div class=fileIcon" + f.t + "></div>" + link + "</span></div>";
}
if (f.t < 3) { html1 += h; } else { html2 += h; }
}
QH('d3serverfiles', html1 + html2);
QE('p3FolderUp', d3filetreelocation.length > 0);
d3setActions();
}
function d3folderset(x) { d3filetreelocation.push(decodeURIComponent(x)); d3updatefiles(); }
function d3folderup(x) { if (x == null) { d3filetreelocation.pop(); } else { while (d3filetreelocation.length > x) { d3filetreelocation.pop(); } } d3updatefiles(); }
function d3getFileSel() { var cc = []; var checkboxes = document.getElementsByName('fcx'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { cc.push(checkboxes[i].value) } } return cc; }
function d3setActions() {
var mode = Q('d3uploadMode').value;
if (mode == 1) {
QE('idx_dlgOkButton', Q('d3localFile').value.length > 0);
} else {
QE('idx_dlgOkButton', d3getFileSel().length == 1);
}
}
//
// NOTIFICATIONS
//
var notifications = [];
// Toggle showing notifications
function clickNotificationIcon(show) {
//addNotification({ icon:0, text:'test' });
if (show == true) { QV('notifiyBox', true); } else if (show == false) { QV('notifiyBox', false); } else { QV('notifiyBox', QS('notifiyBox')['display'] == 'none'); }
drawNotifications();
}
// Set the notification count on the upper right oft he screen
function setNotificationCount(c) {
if (parseInt(Q('notificationCount').innerHTML) == c) return; // If the count did not change, exit now.
QH('notificationCount', c);
QS('notificationCount')['background-color'] = (c == 0)?'lightblue':'orange';
QV('notificationCount', c > 0);
}
// Refresh the notification box
function drawNotifications() {
var r = '';
if (notifications.length == 0) {
r = '<div style=margin:5px>There are currently no notifications</div>';
} else {
for (var i in notifications) {
var n = notifications[i];
var t = '';
var d = new Date(n.time);
var icon = 0;
if (n.nodeid != null) {
var node = getNodeFromId(n.nodeid);
if (node != null) {
//console.log(node);
icon = node.icon;
t = '<b>' + node.name + '</b>: '
}
}
r += '<div title="Occured at ' + d.toLocaleString() + '" id="notifyx' + n.id + '" class=notification style="cursor:pointer;border-top:1px solid ' + ((r == '')?'transparent':'orange') + '"><div class=j' + icon + ' onclick="notificationSelected(' + n.id + ')" style=margin:5px;float:left></div><div onclick="notificationDelete(' + n.id + ')" class=unselectable title="Clear this notification" style=margin:5px;float:right;color:orange><b>X</b></div><div onclick="notificationSelected(' + n.id + ')" style=margin:5px>' + t + n.text + '</div></div>';
}
}
var deleteall = '';
if (notifications.length > 1) { deleteall = '<div id="notifyRemoveAll" onclick="deleteAllNotifications()" style="cursor:pointer;border-top:1px solid orange;margin:5px;color:orange;text-align:right;padding-right:3px">Clear all</div>'; }
QH('notifiyBox', '<div class=customScroll style="max-height:170px;overflow-y:auto;margin:5px">' + r + '</div>' + deleteall );
}
// A notification was selected
function notificationSelected(id) {
var j = -1;
for (var i in notifications) { if (notifications[i].id == id) { j = i; } }
if (j != -1) {
var n = notifications[j];
if (n.nodeid != null) {
if (n.tag == 'desktop') gotoDevice(n.nodeid, 12); // Desktop
else if (n.tag == 'terminal') gotoDevice(n.nodeid, 11); // Terminal
else if (n.tag == 'files') gotoDevice(n.nodeid, 13); // Files
else if (n.tag == 'intelamt') gotoDevice(n.nodeid, 14); // Intel AMT
else if (n.tag == 'console') gotoDevice(n.nodeid, 15); // Files
else gotoDevice(n.nodeid, 10); // General
}
}
}
// Remove one notification
function notificationDelete(id) {
var j = -1; e = Q('notifyx' + id);
if (e != null) {
for (var i in notifications) { if (notifications[i].id == id) { j = i; } }
if (j != -1) {
notifications.splice(j, 1);
e.parentNode.removeChild(e);
setNotificationCount(notifications.length);
if (notifications.length == 0) { QV('notifiyBox', false); }
if (notifications.length == 1) { QV('notifyRemoveAll', false); }
if ((notifications.length > 0) && (j == 0)) {
var n = notifications[0];
QS('notifyx' + n.id)['border-top'] = '1px solid transparent';
}
}
}
}
// Add a new notification and play the notification sound
function addNotification(n) {
if (n.time == null) { n.time = Date.now(); }
if (n.id == null) { n.id = Math.random(); }
notifications.unshift(n);
setNotificationCount(notifications.length);
Q('chimes').play();
clickNotificationIcon(true);
}
// Remove all notifications
function deleteAllNotifications() {
notifications = [];
setNotificationCount(0);
drawNotifications();
QV('notifiyBox', false);
}
//
// POPUP DIALOG
//
// null = Hidden, 1 = Generic Message
var xxdialogMode;
var xxdialogFunc;
var xxdialogButtons;
var xxdialogTag;
var xxcurrentView = 0;
// Display a dialog box
// 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)
function setDialogMode(x, y, b, f, c, tag) {
xxdialogMode = x;
xxdialogFunc = f;
xxdialogButtons = b;
xxdialogTag = tag;
QE('idx_dlgOkButton', true);
QV('idx_dlgOkButton', b & 1);
QV('idx_dlgCancelButton', b & 2);
QV('id_dialogclose', (b & 2) || (b & 8));
QV('idx_dlgDeleteButton', b & 4);
QV('idx_dlgButtonBar', b & 7);
if (y) QH('id_dialogtitle', y);
for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
QV('dialog', x);
if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
}
function dialogclose(x) {
var f = xxdialogFunc;
var b = xxdialogButtons;
var t = xxdialogTag;
setDialogMode();
if (((b & 8) || x) && f) f(x, t);
}
function center() { QS('dialog').left = ((((getDocWidth() - 400) / 2)) + "px"); deskAdjust(); }
function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
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; }
function go(x) {
if (xxdialogMode || xxcurrentView == x) return;
// Edit this line when adding a new screen
for (var i = 0; i < 32; i++) { QV('p' + i, i == x); }
xxcurrentView = x;
QV('topbar', x != 0);
if (x >= 10 && x < 20) { QS('MainMenuMyDevices').backgroundColor = "#606060"; } else { QS('MainMenuMyDevices').backgroundColor = ((x == 1) ? "#003366" : "#808080"); }
if (x >= 20 && x < 30) { QS('MainMenuMyAccount').backgroundColor = "#606060"; } else { QS('MainMenuMyAccount').backgroundColor = ((x == 2) ? "#003366" : "#808080"); }
QS('MainMenuMyEvents').backgroundColor = ((x == 3) ? "#003366" : "#808080");
if (x >= 30 && x < 40) { QS('MainMenuMyUsers').backgroundColor = "#606060"; } else { QS('MainMenuMyUsers').backgroundColor = ((x == 4) ? "#003366" : "#808080"); }
QS('MainMenuMyFiles').backgroundColor = ((x == 5) ? "#003366" : "#808080");
QV('MainSubMenuSpan', x >= 10 && x < 20);
QS('MainDev').backgroundColor = ((x == 10) ? "#003366" : "#808080");
QS('MainDevDesktop').backgroundColor = ((x == 11) ? "#003366" : "#808080");
QS('MainDevTerminal').backgroundColor = ((x == 12) ? "#003366" : "#808080");
QS('MainDevFiles').backgroundColor = ((x == 13) ? "#003366" : "#808080");
QS('MainDevEvents').backgroundColor = ((x == 16) ? "#003366" : "#808080");
QS('MainDevAmt').backgroundColor = ((x == 14) ? "#003366" : "#808080");
QS('MainDevConsole').backgroundColor = ((x == 15) ? "#003366" : "#808080");
QV('MeshSubMenuSpan', x >= 20 && x < 30);
QS('MeshGeneral').backgroundColor = ((x == 20) ? "#003366" : "#808080");
QV('UserSubMenuSpan', x >= 30 && x < 40);
QS('UserGeneral').backgroundColor = ((x == 30) ? "#003366" : "#808080");
QS('UserEvents').backgroundColor = ((x == 31) ? "#003366" : "#808080");
if (x == 1) updateDevices();
}
// Generic methods
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('/'); }
function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
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; } }
function addLink(x, f) { return "<a style=cursor:pointer;color:darkblue;text-decoration:none onclick='" + f + "'>&diams; " + x + "</a>"; }
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
function addOption(q, t, i) { var option = document.createElement("option"); option.text = t; option.value = i; Q(q).add(option); }
function passwordcheck(p) { var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()]).{8,}/; return re.test(p); }
function methodcheck(r) { if (r && r != null && r.Body && r.Body.ReturnValueStr != "SUCCESS") { messagebox("Call Error", r.Header.Method + ": " + r.Body.ReturnValueStr.replace("_", " ")); return true; } return false; }
function TableStart() { return "<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td width=200px><p><td>"; }
function TableStart2() { return "<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td><p><td>"; }
function TableEntry(n, v) { return "<tr><td><p>" + n + "<td>" + v; }
function FullTable(x, e) { var r = TableStart(); for (i in x) { if (i && x[i]) r += TableEntry(i, x[i]); } return r + TableEnd(e); }
function TableEnd(n) { return "<tr><td colspan=2><p>" + (n?n:'') + "</table>"; }
function AddButton(v, f) { return "<input type=button value='" + v + "' onclick='" + f + "' style=margin:4px>"; }
function AddButton2(v, f) { return "<input type=button value='" + v + "' onclick='" + f + "'>"; }
function AddRefreshButton(f) { return "<input type=button name=refreshbtn value=Refresh onclick='refreshButtons(false);" + f + "' style=margin:4px " + (refreshButtonsState==false?"disabled":"") + ">"; }
function MoreStart() { return "<a style=cursor:pointer;color:blue id=morexxx1 onclick=QV(\"morexxx1\",false);QV(\"morexxx2\",true)>&#x25BC; More</a><div id=morexxx2 style=display:none><br><hr>"; };
function MoreEnd() { return "<a style=cursor:pointer;color:blue onclick=QV(\"morexxx2\",false);QV(\"morexxx1\",true)>&#x25B2; Less</a></div>"; };
function getSelectedOptions(sel) { var opts = [], opt; for (var i = 0, len = sel.options.length; i < len; i++) { opt = sel.options[i]; if (opt.selected) { opts.push(opt.value); } } return opts; }
function getInstance(x, y) { for (var i in x) { if (x[i]["InstanceID"] == y) return x[i]; } return null; }
function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); }
function getUrlVars() { var j, hash, vars = [], hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); for (var i = 0; i < hashes.length; i++) { j = hashes[i].indexOf('='); if (j > 0) { vars[hashes[i].substring(0, j)] = hashes[i].substring(j + 1, hashes[i].length); } } return vars; }
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; }
//function addHtmlValue(t, v) { return '<div style=height:20px><div style=float:right;width:220px><b>' + v + '</b></div><div>' + t + '</div></div>'; }
function addHtmlValue(t, v) { return '<table><td style=width:120px>' + t + '<td><b>' + v + '</b></table>'; }
function addHtmlValue2(t, v) { return '<div><div style=display:inline-block;float:right>' + v + '</div><div style=display:inline-block>' + t + '</div></div>'; }
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 = parsedUri[x]; break; } case 1: { r[name] = parsedUri[x]; var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } break; } } } return r; }
function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
</script>
</body>
</html>